mirror of
https://github.com/ppy/osu.git
synced 2024-12-15 01:43:20 +08:00
Merge branch 'ppy:master' into catch-hide-in-relax
This commit is contained in:
commit
c73195fa77
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
@ -4,6 +4,9 @@ concurrency:
|
|||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read # to fetch code (actions/checkout)
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
inspect-code:
|
inspect-code:
|
||||||
name: Code Quality
|
name: Code Quality
|
||||||
|
4
.github/workflows/report-nunit.yml
vendored
4
.github/workflows/report-nunit.yml
vendored
@ -8,8 +8,12 @@ on:
|
|||||||
workflows: ["Continuous Integration"]
|
workflows: ["Continuous Integration"]
|
||||||
types:
|
types:
|
||||||
- completed
|
- completed
|
||||||
|
permissions: {}
|
||||||
jobs:
|
jobs:
|
||||||
annotate:
|
annotate:
|
||||||
|
permissions:
|
||||||
|
checks: write # to create checks (dorny/test-reporter)
|
||||||
|
|
||||||
name: Annotate CI run with test results
|
name: Annotate CI run with test results
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: ${{ github.event.workflow_run.conclusion != 'cancelled' }}
|
if: ${{ github.event.workflow_run.conclusion != 'cancelled' }}
|
||||||
|
3
.github/workflows/sentry-release.yml
vendored
3
.github/workflows/sentry-release.yml
vendored
@ -5,6 +5,9 @@ on:
|
|||||||
tags:
|
tags:
|
||||||
- '*'
|
- '*'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read # to fetch code (actions/checkout)
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
sentry_release:
|
sentry_release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
@ -52,7 +52,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.831.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.831.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.922.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.1005.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Transitive Dependencies">
|
<ItemGroup Label="Transitive Dependencies">
|
||||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
||||||
|
@ -137,12 +137,13 @@ namespace osu.Desktop
|
|||||||
{
|
{
|
||||||
base.SetHost(host);
|
base.SetHost(host);
|
||||||
|
|
||||||
var iconStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico");
|
|
||||||
|
|
||||||
var desktopWindow = (SDL2DesktopWindow)host.Window;
|
var desktopWindow = (SDL2DesktopWindow)host.Window;
|
||||||
|
|
||||||
|
var iconStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico");
|
||||||
|
if (iconStream != null)
|
||||||
|
desktopWindow.SetIconFromStream(iconStream);
|
||||||
|
|
||||||
desktopWindow.CursorState |= CursorState.Hidden;
|
desktopWindow.CursorState |= CursorState.Hidden;
|
||||||
desktopWindow.SetIconFromStream(iconStream);
|
|
||||||
desktopWindow.Title = Name;
|
desktopWindow.Title = Name;
|
||||||
desktopWindow.DragDrop += f => fileDrop(new[] { f });
|
desktopWindow.DragDrop += f => fileDrop(new[] { f });
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Configuration;
|
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
@ -16,22 +15,14 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
{
|
{
|
||||||
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
|
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
|
||||||
|
|
||||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1)
|
||||||
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
|
|
||||||
{
|
{
|
||||||
MinValue = 0.5f,
|
MinValue = 0.5f,
|
||||||
MaxValue = 1.5f,
|
MaxValue = 1.5f,
|
||||||
Default = 1f,
|
|
||||||
Value = 1f,
|
|
||||||
Precision = 0.1f
|
Precision = 0.1f
|
||||||
};
|
};
|
||||||
|
|
||||||
[SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
|
public override BindableBool ComboBasedSize { get; } = new BindableBool(true);
|
||||||
public override BindableBool ComboBasedSize { get; } = new BindableBool
|
|
||||||
{
|
|
||||||
Default = true,
|
|
||||||
Value = true
|
|
||||||
};
|
|
||||||
|
|
||||||
public override float DefaultFlashlightSize => 350;
|
public override float DefaultFlashlightSize => 350;
|
||||||
|
|
||||||
|
@ -6,8 +6,6 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Configuration;
|
|
||||||
using osu.Game.Overlays.Settings;
|
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
@ -17,15 +15,8 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
{
|
{
|
||||||
public override LocalisableString Description => "Where's the catcher?";
|
public override LocalisableString Description => "Where's the catcher?";
|
||||||
|
|
||||||
[SettingSource(
|
public override BindableInt HiddenComboCount { get; } = new BindableInt(10)
|
||||||
"Hidden at combo",
|
|
||||||
"The combo count at which the catcher becomes completely hidden",
|
|
||||||
SettingControlType = typeof(SettingsSlider<int, HiddenComboSlider>)
|
|
||||||
)]
|
|
||||||
public override BindableInt HiddenComboCount { get; } = new BindableInt
|
|
||||||
{
|
{
|
||||||
Default = 10,
|
|
||||||
Value = 10,
|
|
||||||
MinValue = 0,
|
MinValue = 0,
|
||||||
MaxValue = 50,
|
MaxValue = 50,
|
||||||
};
|
};
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Layout;
|
using osu.Framework.Layout;
|
||||||
using osu.Game.Configuration;
|
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -17,22 +16,14 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
public override double ScoreMultiplier => 1;
|
public override double ScoreMultiplier => 1;
|
||||||
public override Type[] IncompatibleMods => new[] { typeof(ModHidden) };
|
public override Type[] IncompatibleMods => new[] { typeof(ModHidden) };
|
||||||
|
|
||||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1)
|
||||||
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
|
|
||||||
{
|
{
|
||||||
MinValue = 0.5f,
|
MinValue = 0.5f,
|
||||||
MaxValue = 3f,
|
MaxValue = 3f,
|
||||||
Default = 1f,
|
|
||||||
Value = 1f,
|
|
||||||
Precision = 0.1f
|
Precision = 0.1f
|
||||||
};
|
};
|
||||||
|
|
||||||
[SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
|
public override BindableBool ComboBasedSize { get; } = new BindableBool();
|
||||||
public override BindableBool ComboBasedSize { get; } = new BindableBool
|
|
||||||
{
|
|
||||||
Default = false,
|
|
||||||
Value = false
|
|
||||||
};
|
|
||||||
|
|
||||||
public override float DefaultFlashlightSize => 50;
|
public override float DefaultFlashlightSize => 50;
|
||||||
|
|
||||||
|
@ -54,10 +54,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateInitialTransforms()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void UpdateStartTimeStateTransforms() => this.FadeOut(150);
|
protected override void UpdateStartTimeStateTransforms() => this.FadeOut(150);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,14 +30,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
|
|
||||||
public bool UpdateResult() => base.UpdateResult(true);
|
public bool UpdateResult() => base.UpdateResult(true);
|
||||||
|
|
||||||
protected override void UpdateInitialTransforms()
|
|
||||||
{
|
|
||||||
base.UpdateInitialTransforms();
|
|
||||||
|
|
||||||
// This hitobject should never expire, so this is just a safe maximum.
|
|
||||||
LifetimeEnd = LifetimeStart + 30000;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void UpdateHitStateTransforms(ArmedState state)
|
protected override void UpdateHitStateTransforms(ArmedState state)
|
||||||
{
|
{
|
||||||
// suppress the base call explicitly.
|
// suppress the base call explicitly.
|
||||||
|
@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
|
|
||||||
public void UpdateResult() => base.UpdateResult(true);
|
public void UpdateResult() => base.UpdateResult(true);
|
||||||
|
|
||||||
protected override double MaximumJudgementOffset => base.MaximumJudgementOffset * release_window_lenience;
|
public override double MaximumJudgementOffset => base.MaximumJudgementOffset * release_window_lenience;
|
||||||
|
|
||||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
|
@ -23,10 +23,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
|
|
||||||
protected readonly IBindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
|
protected readonly IBindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
|
||||||
|
|
||||||
// Leaving the default (10s) makes hitobjects not appear, as this offset is used for the initial state transforms.
|
|
||||||
// Calculated as DrawableManiaRuleset.MAX_TIME_RANGE + some additional allowance for velocity < 1.
|
|
||||||
protected override double InitialLifetimeOffset => 30000;
|
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private ManiaPlayfield playfield { get; set; }
|
private ManiaPlayfield playfield { get; set; }
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
|||||||
|
|
||||||
if (!(currentObj.BaseObject is Spinner))
|
if (!(currentObj.BaseObject is Spinner))
|
||||||
{
|
{
|
||||||
double jumpDistance = (osuHitObject.StackedPosition - currentHitObject.EndPosition).Length;
|
double jumpDistance = (osuHitObject.StackedPosition - currentHitObject.StackedEndPosition).Length;
|
||||||
|
|
||||||
cumulativeStrainTime += lastObj.StrainTime;
|
cumulativeStrainTime += lastObj.StrainTime;
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Configuration;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Mods
|
namespace osu.Game.Rulesets.Osu.Mods
|
||||||
{
|
{
|
||||||
@ -18,13 +17,10 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
|
|
||||||
public override LocalisableString Description => "Hit them at the right size!";
|
public override LocalisableString Description => "Hit them at the right size!";
|
||||||
|
|
||||||
[SettingSource("Starting Size", "The initial size multiplier applied to all objects.")]
|
public override BindableNumber<float> StartScale { get; } = new BindableFloat(2)
|
||||||
public override BindableNumber<float> StartScale { get; } = new BindableFloat
|
|
||||||
{
|
{
|
||||||
MinValue = 1f,
|
MinValue = 1f,
|
||||||
MaxValue = 25f,
|
MaxValue = 25f,
|
||||||
Default = 2f,
|
|
||||||
Value = 2f,
|
|
||||||
Precision = 0.1f,
|
Precision = 0.1f,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -32,22 +32,14 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
Precision = default_follow_delay,
|
Precision = default_follow_delay,
|
||||||
};
|
};
|
||||||
|
|
||||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1)
|
||||||
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
|
|
||||||
{
|
{
|
||||||
MinValue = 0.5f,
|
MinValue = 0.5f,
|
||||||
MaxValue = 2f,
|
MaxValue = 2f,
|
||||||
Default = 1f,
|
|
||||||
Value = 1f,
|
|
||||||
Precision = 0.1f
|
Precision = 0.1f
|
||||||
};
|
};
|
||||||
|
|
||||||
[SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
|
public override BindableBool ComboBasedSize { get; } = new BindableBool(true);
|
||||||
public override BindableBool ComboBasedSize { get; } = new BindableBool
|
|
||||||
{
|
|
||||||
Default = true,
|
|
||||||
Value = true
|
|
||||||
};
|
|
||||||
|
|
||||||
public override float DefaultFlashlightSize => 180;
|
public override float DefaultFlashlightSize => 180;
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Configuration;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Mods
|
namespace osu.Game.Rulesets.Osu.Mods
|
||||||
{
|
{
|
||||||
@ -18,13 +17,10 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
|
|
||||||
public override LocalisableString Description => "Hit them at the right size!";
|
public override LocalisableString Description => "Hit them at the right size!";
|
||||||
|
|
||||||
[SettingSource("Starting Size", "The initial size multiplier applied to all objects.")]
|
public override BindableNumber<float> StartScale { get; } = new BindableFloat(0.5f)
|
||||||
public override BindableNumber<float> StartScale { get; } = new BindableFloat
|
|
||||||
{
|
{
|
||||||
MinValue = 0f,
|
MinValue = 0f,
|
||||||
MaxValue = 0.99f,
|
MaxValue = 0.99f,
|
||||||
Default = 0.5f,
|
|
||||||
Value = 0.5f,
|
|
||||||
Precision = 0.01f,
|
Precision = 0.01f,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,6 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
|
||||||
using osu.Game.Overlays.Settings;
|
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
@ -22,15 +20,8 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
|
|
||||||
private PeriodTracker spinnerPeriods = null!;
|
private PeriodTracker spinnerPeriods = null!;
|
||||||
|
|
||||||
[SettingSource(
|
public override BindableInt HiddenComboCount { get; } = new BindableInt(10)
|
||||||
"Hidden at combo",
|
|
||||||
"The combo count at which the cursor becomes completely hidden",
|
|
||||||
SettingControlType = typeof(SettingsSlider<int, HiddenComboSlider>)
|
|
||||||
)]
|
|
||||||
public override BindableInt HiddenComboCount { get; } = new BindableInt
|
|
||||||
{
|
{
|
||||||
Default = 10,
|
|
||||||
Value = 10,
|
|
||||||
MinValue = 0,
|
MinValue = 0,
|
||||||
MaxValue = 50,
|
MaxValue = 50,
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
@ -20,6 +21,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
|
|
||||||
public override double ScoreMultiplier => 1;
|
public override double ScoreMultiplier => 1;
|
||||||
|
|
||||||
|
[SettingSource("Starting Size", "The initial size multiplier applied to all objects.")]
|
||||||
public abstract BindableNumber<float> StartScale { get; }
|
public abstract BindableNumber<float> StartScale { get; }
|
||||||
|
|
||||||
protected virtual float EndScale => 1;
|
protected virtual float EndScale => 1;
|
||||||
|
@ -29,10 +29,8 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModTarget)).ToArray();
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModTarget)).ToArray();
|
||||||
|
|
||||||
[SettingSource("Angle sharpness", "How sharp angles should be", SettingControlType = typeof(SettingsSlider<float>))]
|
[SettingSource("Angle sharpness", "How sharp angles should be", SettingControlType = typeof(SettingsSlider<float>))]
|
||||||
public BindableFloat AngleSharpness { get; } = new BindableFloat
|
public BindableFloat AngleSharpness { get; } = new BindableFloat(7)
|
||||||
{
|
{
|
||||||
Default = 7,
|
|
||||||
Value = 7,
|
|
||||||
MinValue = 1,
|
MinValue = 1,
|
||||||
MaxValue = 10,
|
MaxValue = 10,
|
||||||
Precision = 0.1f
|
Precision = 0.1f
|
||||||
|
@ -53,11 +53,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
}).ToArray();
|
}).ToArray();
|
||||||
|
|
||||||
[SettingSource("Seed", "Use a custom seed instead of a random one", SettingControlType = typeof(SettingsNumberBox))]
|
[SettingSource("Seed", "Use a custom seed instead of a random one", SettingControlType = typeof(SettingsNumberBox))]
|
||||||
public Bindable<int?> Seed { get; } = new Bindable<int?>
|
public Bindable<int?> Seed { get; } = new Bindable<int?>();
|
||||||
{
|
|
||||||
Default = null,
|
|
||||||
Value = null
|
|
||||||
};
|
|
||||||
|
|
||||||
[SettingSource("Metronome ticks", "Whether a metronome beat should play in the background")]
|
[SettingSource("Metronome ticks", "Whether a metronome beat should play in the background")]
|
||||||
public Bindable<bool> Metronome { get; } = new BindableBool(true);
|
public Bindable<bool> Metronome { get; } = new BindableBool(true);
|
||||||
|
@ -204,12 +204,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
// todo: temporary / arbitrary, used for lifetime optimisation.
|
// todo: temporary / arbitrary, used for lifetime optimisation.
|
||||||
this.Delay(800).FadeOut();
|
this.Delay(800).FadeOut();
|
||||||
|
|
||||||
// in the case of an early state change, the fade should be expedited to the current point in time.
|
|
||||||
if (HitStateUpdateTime < HitObject.StartTime)
|
|
||||||
ApproachCircle.FadeOut(50);
|
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
|
default:
|
||||||
|
ApproachCircle.FadeOut();
|
||||||
|
break;
|
||||||
|
|
||||||
case ArmedState.Idle:
|
case ArmedState.Idle:
|
||||||
HitArea.HitAction = null;
|
HitArea.HitAction = null;
|
||||||
break;
|
break;
|
||||||
|
@ -11,7 +11,9 @@ using osu.Framework.Graphics.Primitives;
|
|||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
|
using osu.Game.Rulesets.Osu.Scoring;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||||
{
|
{
|
||||||
@ -64,6 +66,23 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
ScaleBindable.UnbindFrom(HitObject.ScaleBindable);
|
ScaleBindable.UnbindFrom(HitObject.ScaleBindable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void UpdateInitialTransforms()
|
||||||
|
{
|
||||||
|
base.UpdateInitialTransforms();
|
||||||
|
|
||||||
|
// Dim should only be applied at a top level, as it will be implicitly applied to nested objects.
|
||||||
|
if (ParentHitObject == null)
|
||||||
|
{
|
||||||
|
// Of note, no one noticed this was missing for years, but it definitely feels like it should still exist.
|
||||||
|
// For now this is applied across all skins, and matches stable.
|
||||||
|
// For simplicity, dim colour is applied to the DrawableHitObject itself.
|
||||||
|
// We may need to make a nested container setup if this even causes a usage conflict (ie. with a mod).
|
||||||
|
this.FadeColour(new Color4(195, 195, 195, 255));
|
||||||
|
using (BeginDelayedSequence(InitialLifetimeOffset - OsuHitWindows.MISS_WINDOW))
|
||||||
|
this.FadeColour(Color4.White, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt;
|
protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt;
|
||||||
|
|
||||||
private OsuInputManager osuActionInputManager;
|
private OsuInputManager osuActionInputManager;
|
||||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override double MaximumJudgementOffset => DrawableSpinner.HitObject.Duration;
|
public override double MaximumJudgementOffset => DrawableSpinner.HitObject.Duration;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Apply a judgement result.
|
/// Apply a judgement result.
|
||||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
// This is so on repeats ticks don't appear too late to be visually processed by the player.
|
// This is so on repeats ticks don't appear too late to be visually processed by the player.
|
||||||
offset = 200;
|
offset = 200;
|
||||||
else
|
else
|
||||||
offset = TimeFadeIn * 0.66f;
|
offset = TimePreempt * 0.66f;
|
||||||
|
|
||||||
TimePreempt = (StartTime - SpanStartTime) / 2 + offset;
|
TimePreempt = (StartTime - SpanStartTime) / 2 + offset;
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,23 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Scoring
|
namespace osu.Game.Rulesets.Osu.Scoring
|
||||||
{
|
{
|
||||||
public class OsuHitWindows : HitWindows
|
public class OsuHitWindows : HitWindows
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// osu! ruleset has a fixed miss window regardless of difficulty settings.
|
||||||
|
/// </summary>
|
||||||
|
public const double MISS_WINDOW = 400;
|
||||||
|
|
||||||
private static readonly DifficultyRange[] osu_ranges =
|
private static readonly DifficultyRange[] osu_ranges =
|
||||||
{
|
{
|
||||||
new DifficultyRange(HitResult.Great, 80, 50, 20),
|
new DifficultyRange(HitResult.Great, 80, 50, 20),
|
||||||
new DifficultyRange(HitResult.Ok, 140, 100, 60),
|
new DifficultyRange(HitResult.Ok, 140, 100, 60),
|
||||||
new DifficultyRange(HitResult.Meh, 200, 150, 100),
|
new DifficultyRange(HitResult.Meh, 200, 150, 100),
|
||||||
new DifficultyRange(HitResult.Miss, 400, 400, 400),
|
new DifficultyRange(HitResult.Miss, MISS_WINDOW, MISS_WINDOW, MISS_WINDOW),
|
||||||
};
|
};
|
||||||
|
|
||||||
public override bool IsHitResultAllowed(HitResult result)
|
public override bool IsHitResultAllowed(HitResult result)
|
||||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon
|
|||||||
};
|
};
|
||||||
|
|
||||||
accentColour = hitObject.AccentColour.GetBoundCopy();
|
accentColour = hitObject.AccentColour.GetBoundCopy();
|
||||||
accentColour.BindValueChanged(accent => BorderColour = accent.NewValue);
|
accentColour.BindValueChanged(accent => BorderColour = accent.NewValue, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Replays;
|
using osu.Game.Rulesets.Replays;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
@ -129,5 +130,32 @@ namespace osu.Game.Rulesets.Taiko.Tests.Judgements
|
|||||||
AssertResult<Hit>(0, HitResult.Miss);
|
AssertResult<Hit>(0, HitResult.Miss);
|
||||||
AssertResult<StrongNestedHitObject>(0, HitResult.IgnoreMiss);
|
AssertResult<StrongNestedHitObject>(0, HitResult.IgnoreMiss);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestHighVelocityHit()
|
||||||
|
{
|
||||||
|
const double hit_time = 1000;
|
||||||
|
|
||||||
|
var beatmap = CreateBeatmap(new Hit
|
||||||
|
{
|
||||||
|
Type = HitType.Centre,
|
||||||
|
StartTime = hit_time,
|
||||||
|
});
|
||||||
|
|
||||||
|
beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 6 });
|
||||||
|
beatmap.ControlPointInfo.Add(0, new EffectControlPoint { ScrollSpeed = 10 });
|
||||||
|
|
||||||
|
var hitWindows = new HitWindows();
|
||||||
|
hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty);
|
||||||
|
|
||||||
|
PerformTest(new List<ReplayFrame>
|
||||||
|
{
|
||||||
|
new TaikoReplayFrame(0),
|
||||||
|
new TaikoReplayFrame(hit_time - hitWindows.WindowFor(HitResult.Great), TaikoAction.LeftCentre),
|
||||||
|
}, beatmap);
|
||||||
|
|
||||||
|
AssertJudgementCount(1);
|
||||||
|
AssertResult<Hit>(0, HitResult.Ok);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
private int countOk;
|
private int countOk;
|
||||||
private int countMeh;
|
private int countMeh;
|
||||||
private int countMiss;
|
private int countMiss;
|
||||||
|
private double accuracy;
|
||||||
|
|
||||||
private double effectiveMissCount;
|
private double effectiveMissCount;
|
||||||
|
|
||||||
@ -36,6 +37,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
countOk = score.Statistics.GetValueOrDefault(HitResult.Ok);
|
countOk = score.Statistics.GetValueOrDefault(HitResult.Ok);
|
||||||
countMeh = score.Statistics.GetValueOrDefault(HitResult.Meh);
|
countMeh = score.Statistics.GetValueOrDefault(HitResult.Meh);
|
||||||
countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss);
|
countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss);
|
||||||
|
accuracy = customAccuracy;
|
||||||
|
|
||||||
// The effectiveMissCount is calculated by gaining a ratio for totalSuccessfulHits and increasing the miss penalty for shorter object counts lower than 1000.
|
// The effectiveMissCount is calculated by gaining a ratio for totalSuccessfulHits and increasing the miss penalty for shorter object counts lower than 1000.
|
||||||
if (totalSuccessfulHits > 0)
|
if (totalSuccessfulHits > 0)
|
||||||
@ -87,7 +89,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
if (score.Mods.Any(m => m is ModFlashlight<TaikoHitObject>))
|
if (score.Mods.Any(m => m is ModFlashlight<TaikoHitObject>))
|
||||||
difficultyValue *= 1.050 * lengthBonus;
|
difficultyValue *= 1.050 * lengthBonus;
|
||||||
|
|
||||||
return difficultyValue * Math.Pow(score.Accuracy, 2.0);
|
return difficultyValue * Math.Pow(accuracy, 2.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private double computeAccuracyValue(ScoreInfo score, TaikoDifficultyAttributes attributes)
|
private double computeAccuracyValue(ScoreInfo score, TaikoDifficultyAttributes attributes)
|
||||||
@ -95,7 +97,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
if (attributes.GreatHitWindow <= 0)
|
if (attributes.GreatHitWindow <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
double accuracyValue = Math.Pow(60.0 / attributes.GreatHitWindow, 1.1) * Math.Pow(score.Accuracy, 8.0) * Math.Pow(attributes.StarRating, 0.4) * 27.0;
|
double accuracyValue = Math.Pow(60.0 / attributes.GreatHitWindow, 1.1) * Math.Pow(accuracy, 8.0) * Math.Pow(attributes.StarRating, 0.4) * 27.0;
|
||||||
|
|
||||||
double lengthBonus = Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3));
|
double lengthBonus = Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3));
|
||||||
accuracyValue *= lengthBonus;
|
accuracyValue *= lengthBonus;
|
||||||
@ -110,5 +112,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
private int totalHits => countGreat + countOk + countMeh + countMiss;
|
private int totalHits => countGreat + countOk + countMeh + countMiss;
|
||||||
|
|
||||||
private int totalSuccessfulHits => countGreat + countOk + countMeh;
|
private int totalSuccessfulHits => countGreat + countOk + countMeh;
|
||||||
|
|
||||||
|
private double customAccuracy => totalHits > 0 ? (countGreat * 300 + countOk * 150) / (totalHits * 300.0) : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Layout;
|
using osu.Framework.Layout;
|
||||||
using osu.Game.Configuration;
|
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
using osu.Game.Rulesets.Taiko.UI;
|
using osu.Game.Rulesets.Taiko.UI;
|
||||||
@ -17,22 +16,14 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
{
|
{
|
||||||
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
|
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
|
||||||
|
|
||||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1)
|
||||||
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
|
|
||||||
{
|
{
|
||||||
MinValue = 0.5f,
|
MinValue = 0.5f,
|
||||||
MaxValue = 1.5f,
|
MaxValue = 1.5f,
|
||||||
Default = 1f,
|
|
||||||
Value = 1f,
|
|
||||||
Precision = 0.1f
|
Precision = 0.1f
|
||||||
};
|
};
|
||||||
|
|
||||||
[SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
|
public override BindableBool ComboBasedSize { get; } = new BindableBool(true);
|
||||||
public override BindableBool ComboBasedSize { get; } = new BindableBool
|
|
||||||
{
|
|
||||||
Default = true,
|
|
||||||
Value = true
|
|
||||||
};
|
|
||||||
|
|
||||||
public override float DefaultFlashlightSize => 250;
|
public override float DefaultFlashlightSize => 250;
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
Filled = HitObject.FirstTick
|
Filled = HitObject.FirstTick
|
||||||
});
|
});
|
||||||
|
|
||||||
protected override double MaximumJudgementOffset => HitObject.HitWindow;
|
public override double MaximumJudgementOffset => HitObject.HitWindow;
|
||||||
|
|
||||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
|
@ -204,31 +204,23 @@ namespace osu.Game.Tests.Online
|
|||||||
public override double ScoreMultiplier => 1;
|
public override double ScoreMultiplier => 1;
|
||||||
|
|
||||||
[SettingSource("Initial rate", "The starting speed of the track")]
|
[SettingSource("Initial rate", "The starting speed of the track")]
|
||||||
public override BindableNumber<double> InitialRate { get; } = new BindableDouble
|
public override BindableNumber<double> InitialRate { get; } = new BindableDouble(1.5)
|
||||||
{
|
{
|
||||||
MinValue = 1,
|
MinValue = 1,
|
||||||
MaxValue = 2,
|
MaxValue = 2,
|
||||||
Default = 1.5,
|
|
||||||
Value = 1.5,
|
|
||||||
Precision = 0.01,
|
Precision = 0.01,
|
||||||
};
|
};
|
||||||
|
|
||||||
[SettingSource("Final rate", "The speed increase to ramp towards")]
|
[SettingSource("Final rate", "The speed increase to ramp towards")]
|
||||||
public override BindableNumber<double> FinalRate { get; } = new BindableDouble
|
public override BindableNumber<double> FinalRate { get; } = new BindableDouble(0.5)
|
||||||
{
|
{
|
||||||
MinValue = 0,
|
MinValue = 0,
|
||||||
MaxValue = 1,
|
MaxValue = 1,
|
||||||
Default = 0.5,
|
|
||||||
Value = 0.5,
|
|
||||||
Precision = 0.01,
|
Precision = 0.01,
|
||||||
};
|
};
|
||||||
|
|
||||||
[SettingSource("Adjust pitch", "Should pitch be adjusted with speed")]
|
[SettingSource("Adjust pitch", "Should pitch be adjusted with speed")]
|
||||||
public override BindableBool AdjustPitch { get; } = new BindableBool
|
public override BindableBool AdjustPitch { get; } = new BindableBool(true);
|
||||||
{
|
|
||||||
Default = true,
|
|
||||||
Value = true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestModDifficultyAdjust : ModDifficultyAdjust
|
private class TestModDifficultyAdjust : ModDifficultyAdjust
|
||||||
|
@ -124,31 +124,23 @@ namespace osu.Game.Tests.Online
|
|||||||
public override double ScoreMultiplier => 1;
|
public override double ScoreMultiplier => 1;
|
||||||
|
|
||||||
[SettingSource("Initial rate", "The starting speed of the track")]
|
[SettingSource("Initial rate", "The starting speed of the track")]
|
||||||
public override BindableNumber<double> InitialRate { get; } = new BindableDouble
|
public override BindableNumber<double> InitialRate { get; } = new BindableDouble(1.5)
|
||||||
{
|
{
|
||||||
MinValue = 1,
|
MinValue = 1,
|
||||||
MaxValue = 2,
|
MaxValue = 2,
|
||||||
Default = 1.5,
|
|
||||||
Value = 1.5,
|
|
||||||
Precision = 0.01,
|
Precision = 0.01,
|
||||||
};
|
};
|
||||||
|
|
||||||
[SettingSource("Final rate", "The speed increase to ramp towards")]
|
[SettingSource("Final rate", "The speed increase to ramp towards")]
|
||||||
public override BindableNumber<double> FinalRate { get; } = new BindableDouble
|
public override BindableNumber<double> FinalRate { get; } = new BindableDouble(0.5)
|
||||||
{
|
{
|
||||||
MinValue = 0,
|
MinValue = 0,
|
||||||
MaxValue = 1,
|
MaxValue = 1,
|
||||||
Default = 0.5,
|
|
||||||
Value = 0.5,
|
|
||||||
Precision = 0.01,
|
Precision = 0.01,
|
||||||
};
|
};
|
||||||
|
|
||||||
[SettingSource("Adjust pitch", "Should pitch be adjusted with speed")]
|
[SettingSource("Adjust pitch", "Should pitch be adjusted with speed")]
|
||||||
public override BindableBool AdjustPitch { get; } = new BindableBool
|
public override BindableBool AdjustPitch { get; } = new BindableBool(true);
|
||||||
{
|
|
||||||
Default = true,
|
|
||||||
Value = true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestModEnum : Mod
|
private class TestModEnum : Mod
|
||||||
|
@ -8,7 +8,6 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -78,7 +77,7 @@ namespace osu.Game.Tests.Online
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
beatmaps.AllowImport = new TaskCompletionSource<bool>();
|
beatmaps.AllowImport.Reset();
|
||||||
|
|
||||||
testBeatmapFile = TestResources.GetQuickTestBeatmapForImport();
|
testBeatmapFile = TestResources.GetQuickTestBeatmapForImport();
|
||||||
|
|
||||||
@ -132,7 +131,7 @@ namespace osu.Game.Tests.Online
|
|||||||
AddStep("finish download", () => ((TestDownloadRequest)beatmapDownloader.GetExistingDownload(testBeatmapSet))!.TriggerSuccess(testBeatmapFile));
|
AddStep("finish download", () => ((TestDownloadRequest)beatmapDownloader.GetExistingDownload(testBeatmapSet))!.TriggerSuccess(testBeatmapFile));
|
||||||
addAvailabilityCheckStep("state importing", BeatmapAvailability.Importing);
|
addAvailabilityCheckStep("state importing", BeatmapAvailability.Importing);
|
||||||
|
|
||||||
AddStep("allow importing", () => beatmaps.AllowImport.SetResult(true));
|
AddStep("allow importing", () => beatmaps.AllowImport.Set());
|
||||||
AddUntilStep("wait for import", () => beatmaps.CurrentImport != null);
|
AddUntilStep("wait for import", () => beatmaps.CurrentImport != null);
|
||||||
AddUntilStep("ensure beatmap available", () => beatmaps.IsAvailableLocally(testBeatmapSet));
|
AddUntilStep("ensure beatmap available", () => beatmaps.IsAvailableLocally(testBeatmapSet));
|
||||||
addAvailabilityCheckStep("state is locally available", BeatmapAvailability.LocallyAvailable);
|
addAvailabilityCheckStep("state is locally available", BeatmapAvailability.LocallyAvailable);
|
||||||
@ -141,7 +140,7 @@ namespace osu.Game.Tests.Online
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestTrackerRespectsSoftDeleting()
|
public void TestTrackerRespectsSoftDeleting()
|
||||||
{
|
{
|
||||||
AddStep("allow importing", () => beatmaps.AllowImport.SetResult(true));
|
AddStep("allow importing", () => beatmaps.AllowImport.Set());
|
||||||
AddStep("import beatmap", () => beatmaps.Import(testBeatmapFile).WaitSafely());
|
AddStep("import beatmap", () => beatmaps.Import(testBeatmapFile).WaitSafely());
|
||||||
addAvailabilityCheckStep("state locally available", BeatmapAvailability.LocallyAvailable);
|
addAvailabilityCheckStep("state locally available", BeatmapAvailability.LocallyAvailable);
|
||||||
|
|
||||||
@ -155,7 +154,7 @@ namespace osu.Game.Tests.Online
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestTrackerRespectsChecksum()
|
public void TestTrackerRespectsChecksum()
|
||||||
{
|
{
|
||||||
AddStep("allow importing", () => beatmaps.AllowImport.SetResult(true));
|
AddStep("allow importing", () => beatmaps.AllowImport.Set());
|
||||||
AddStep("import beatmap", () => beatmaps.Import(testBeatmapFile).WaitSafely());
|
AddStep("import beatmap", () => beatmaps.Import(testBeatmapFile).WaitSafely());
|
||||||
addAvailabilityCheckStep("initially locally available", BeatmapAvailability.LocallyAvailable);
|
addAvailabilityCheckStep("initially locally available", BeatmapAvailability.LocallyAvailable);
|
||||||
|
|
||||||
@ -202,7 +201,7 @@ namespace osu.Game.Tests.Online
|
|||||||
|
|
||||||
private class TestBeatmapManager : BeatmapManager
|
private class TestBeatmapManager : BeatmapManager
|
||||||
{
|
{
|
||||||
public TaskCompletionSource<bool> AllowImport = new TaskCompletionSource<bool>();
|
public readonly ManualResetEventSlim AllowImport = new ManualResetEventSlim();
|
||||||
|
|
||||||
public Live<BeatmapSetInfo> CurrentImport { get; private set; }
|
public Live<BeatmapSetInfo> CurrentImport { get; private set; }
|
||||||
|
|
||||||
@ -229,7 +228,9 @@ namespace osu.Game.Tests.Online
|
|||||||
|
|
||||||
public override Live<BeatmapSetInfo> ImportModel(BeatmapSetInfo item, ArchiveReader archive = null, bool batchImport = false, CancellationToken cancellationToken = default)
|
public override Live<BeatmapSetInfo> ImportModel(BeatmapSetInfo item, ArchiveReader archive = null, bool batchImport = false, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
testBeatmapManager.AllowImport.Task.WaitSafely();
|
if (!testBeatmapManager.AllowImport.Wait(TimeSpan.FromSeconds(10), cancellationToken))
|
||||||
|
throw new TimeoutException("Timeout waiting for import to be allowed.");
|
||||||
|
|
||||||
return (testBeatmapManager.CurrentImport = base.ImportModel(item, archive, batchImport, cancellationToken));
|
return (testBeatmapManager.CurrentImport = base.ImportModel(item, archive, batchImport, cancellationToken));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,16 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
AddUntilStep("wait for some scores not masked away",
|
AddUntilStep("wait for some scores not masked away",
|
||||||
() => leaderboard.ChildrenOfType<GameplayLeaderboardScore>().Any(s => leaderboard.ScreenSpaceDrawQuad.Contains(s.ScreenSpaceDrawQuad.Centre)));
|
() => leaderboard.ChildrenOfType<GameplayLeaderboardScore>().Any(s => leaderboard.ScreenSpaceDrawQuad.Contains(s.ScreenSpaceDrawQuad.Centre)));
|
||||||
|
|
||||||
|
AddUntilStep("wait for tracked score fully visible", () => leaderboard.ScreenSpaceDrawQuad.Intersects(leaderboard.TrackedScore!.ScreenSpaceDrawQuad));
|
||||||
|
|
||||||
|
AddStep("change score to middle", () => playerScore.Value = 1000000);
|
||||||
|
AddWaitStep("wait for movement", 5);
|
||||||
|
AddUntilStep("wait for tracked score fully visible", () => leaderboard.ScreenSpaceDrawQuad.Intersects(leaderboard.TrackedScore!.ScreenSpaceDrawQuad));
|
||||||
|
|
||||||
|
AddStep("change score to first", () => playerScore.Value = 5000000);
|
||||||
|
AddWaitStep("wait for movement", 5);
|
||||||
|
AddUntilStep("wait for tracked score fully visible", () => leaderboard.ScreenSpaceDrawQuad.Intersects(leaderboard.TrackedScore!.ScreenSpaceDrawQuad));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -11,8 +11,10 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
|
using osu.Framework.Timing;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
@ -167,14 +169,39 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddStep("add control points", () => addControlPoints(testControlPoints, Time.Current));
|
AddStep("add control points", () => addControlPoints(testControlPoints, Time.Current));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addHitObject(double time)
|
[Test]
|
||||||
|
public void TestVeryFlowScroll()
|
||||||
|
{
|
||||||
|
const double long_time_range = 100000;
|
||||||
|
var manualClock = new ManualClock();
|
||||||
|
|
||||||
|
AddStep("set manual clock", () =>
|
||||||
|
{
|
||||||
|
manualClock.CurrentTime = 0;
|
||||||
|
scrollContainers.ForEach(c => c.Clock = new FramedClock(manualClock));
|
||||||
|
|
||||||
|
setScrollAlgorithm(ScrollVisualisationMethod.Constant);
|
||||||
|
scrollContainers.ForEach(c => c.TimeRange = long_time_range);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("add hit objects", () =>
|
||||||
|
{
|
||||||
|
addHitObject(long_time_range);
|
||||||
|
addHitObject(long_time_range + 100, 250);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAssert("hit objects are alive", () => playfields.All(p => p.HitObjectContainer.AliveObjects.Count() == 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addHitObject(double time, float size = 75)
|
||||||
{
|
{
|
||||||
playfields.ForEach(p =>
|
playfields.ForEach(p =>
|
||||||
{
|
{
|
||||||
var hitObject = new TestDrawableHitObject(time);
|
var hitObject = new TestHitObject(size) { StartTime = time };
|
||||||
setAnchor(hitObject, p);
|
var drawable = new TestDrawableHitObject(hitObject);
|
||||||
|
|
||||||
p.Add(hitObject);
|
setAnchor(drawable, p);
|
||||||
|
p.Add(drawable);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,6 +275,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override ScrollingHitObjectContainer CreateScrollingHitObjectContainer() => new TestScrollingHitObjectContainer();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestDrawableControlPoint : DrawableHitObject<HitObject>
|
private class TestDrawableControlPoint : DrawableHitObject<HitObject>
|
||||||
@ -281,22 +310,41 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestDrawableHitObject : DrawableHitObject<HitObject>
|
private class TestHitObject : HitObject
|
||||||
{
|
{
|
||||||
public TestDrawableHitObject(double time)
|
public readonly float Size;
|
||||||
: base(new HitObject { StartTime = time, HitWindows = HitWindows.Empty })
|
|
||||||
{
|
|
||||||
Origin = Anchor.Custom;
|
|
||||||
OriginPosition = new Vector2(75 / 4.0f);
|
|
||||||
|
|
||||||
AutoSizeAxes = Axes.Both;
|
public TestHitObject(float size)
|
||||||
|
{
|
||||||
|
Size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestDrawableHitObject : DrawableHitObject<TestHitObject>
|
||||||
|
{
|
||||||
|
public TestDrawableHitObject(TestHitObject hitObject)
|
||||||
|
: base(hitObject)
|
||||||
|
{
|
||||||
|
Origin = Anchor.Centre;
|
||||||
|
Size = new Vector2(hitObject.Size);
|
||||||
|
|
||||||
AddInternal(new Box
|
AddInternal(new Box
|
||||||
{
|
{
|
||||||
Size = new Vector2(75),
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = new Color4(RNG.NextSingle(), RNG.NextSingle(), RNG.NextSingle(), 1)
|
Colour = new Color4(RNG.NextSingle(), RNG.NextSingle(), RNG.NextSingle(), 1)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class TestScrollingHitObjectContainer : ScrollingHitObjectContainer
|
||||||
|
{
|
||||||
|
protected override RectangleF GetConservativeBoundingBox(HitObjectLifetimeEntry entry)
|
||||||
|
{
|
||||||
|
if (entry.HitObject is TestHitObject testObject)
|
||||||
|
return new RectangleF().Inflate(testObject.Size / 2);
|
||||||
|
|
||||||
|
return base.GetConservativeBoundingBox(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -24,6 +25,16 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
private readonly BindableList<ScoreInfo> scores = new BindableList<ScoreInfo>();
|
private readonly BindableList<ScoreInfo> scores = new BindableList<ScoreInfo>();
|
||||||
|
|
||||||
|
private readonly Bindable<bool> configVisibility = new Bindable<bool>();
|
||||||
|
|
||||||
|
private SoloGameplayLeaderboard leaderboard = null!;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuConfigManager config)
|
||||||
|
{
|
||||||
|
config.BindWith(OsuSetting.GameplayLeaderboard, configVisibility);
|
||||||
|
}
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
public void SetUpSteps()
|
public void SetUpSteps()
|
||||||
{
|
{
|
||||||
@ -37,11 +48,12 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
Id = 2,
|
Id = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
Child = new SoloGameplayLeaderboard(trackingUser)
|
Child = leaderboard = new SoloGameplayLeaderboard(trackingUser)
|
||||||
{
|
{
|
||||||
Scores = { BindTarget = scores },
|
Scores = { BindTarget = scores },
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
AlwaysVisible = { Value = false },
|
||||||
Expanded = { Value = true },
|
Expanded = { Value = true },
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -54,7 +66,24 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
AddSliderStep("score", 0, 1000000, 500000, v => scoreProcessor.TotalScore.Value = v);
|
AddSliderStep("score", 0, 1000000, 500000, v => scoreProcessor.TotalScore.Value = v);
|
||||||
AddSliderStep("accuracy", 0f, 1f, 0.5f, v => scoreProcessor.Accuracy.Value = v);
|
AddSliderStep("accuracy", 0f, 1f, 0.5f, v => scoreProcessor.Accuracy.Value = v);
|
||||||
AddSliderStep("combo", 0, 1000, 0, v => scoreProcessor.Combo.Value = v);
|
AddSliderStep("combo", 0, 10000, 0, v => scoreProcessor.HighestCombo.Value = v);
|
||||||
|
AddStep("toggle expanded", () => leaderboard.Expanded.Value = !leaderboard.Expanded.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestVisibility()
|
||||||
|
{
|
||||||
|
AddStep("set config visible true", () => configVisibility.Value = true);
|
||||||
|
AddUntilStep("leaderboard visible", () => leaderboard.Alpha == 1);
|
||||||
|
|
||||||
|
AddStep("set config visible false", () => configVisibility.Value = false);
|
||||||
|
AddUntilStep("leaderboard not visible", () => leaderboard.Alpha == 0);
|
||||||
|
|
||||||
|
AddStep("set always visible", () => leaderboard.AlwaysVisible.Value = true);
|
||||||
|
AddUntilStep("leaderboard visible", () => leaderboard.Alpha == 1);
|
||||||
|
|
||||||
|
AddStep("set config visible true", () => configVisibility.Value = true);
|
||||||
|
AddAssert("leaderboard still visible", () => leaderboard.Alpha == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<ScoreInfo> createSampleScores()
|
private static List<ScoreInfo> createSampleScores()
|
||||||
|
@ -32,6 +32,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
protected new OutroPlayer Player => (OutroPlayer)base.Player;
|
protected new OutroPlayer Player => (OutroPlayer)base.Player;
|
||||||
|
|
||||||
|
private double currentBeatmapDuration;
|
||||||
private double currentStoryboardDuration;
|
private double currentStoryboardDuration;
|
||||||
|
|
||||||
private bool showResults = true;
|
private bool showResults = true;
|
||||||
@ -45,7 +46,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddStep("enable storyboard", () => LocalConfig.SetValue(OsuSetting.ShowStoryboard, true));
|
AddStep("enable storyboard", () => LocalConfig.SetValue(OsuSetting.ShowStoryboard, true));
|
||||||
AddStep("set dim level to 0", () => LocalConfig.SetValue<double>(OsuSetting.DimLevel, 0));
|
AddStep("set dim level to 0", () => LocalConfig.SetValue<double>(OsuSetting.DimLevel, 0));
|
||||||
AddStep("reset fail conditions", () => currentFailConditions = (_, _) => false);
|
AddStep("reset fail conditions", () => currentFailConditions = (_, _) => false);
|
||||||
AddStep("set storyboard duration to 2s", () => currentStoryboardDuration = 2000);
|
AddStep("set beatmap duration to 0s", () => currentBeatmapDuration = 0);
|
||||||
|
AddStep("set storyboard duration to 8s", () => currentStoryboardDuration = 8000);
|
||||||
AddStep("set ShowResults = true", () => showResults = true);
|
AddStep("set ShowResults = true", () => showResults = true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,6 +153,24 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddAssert("player exited", () => Stack.CurrentScreen == null);
|
AddAssert("player exited", () => Stack.CurrentScreen == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPerformExitAfterOutro()
|
||||||
|
{
|
||||||
|
CreateTest(() =>
|
||||||
|
{
|
||||||
|
AddStep("set beatmap duration to 4s", () => currentBeatmapDuration = 4000);
|
||||||
|
AddStep("set storyboard duration to 1s", () => currentStoryboardDuration = 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.CurrentTime >= currentStoryboardDuration);
|
||||||
|
AddStep("exit via pause", () => Player.ExitViaPause());
|
||||||
|
AddAssert("player paused", () => !Player.IsResuming);
|
||||||
|
|
||||||
|
AddStep("resume player", () => Player.Resume());
|
||||||
|
AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value);
|
||||||
|
AddUntilStep("wait for score shown", () => Player.IsScoreShown);
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool AllowFail => true;
|
protected override bool AllowFail => true;
|
||||||
|
|
||||||
protected override Ruleset CreatePlayerRuleset() => new OsuRuleset();
|
protected override Ruleset CreatePlayerRuleset() => new OsuRuleset();
|
||||||
@ -160,7 +180,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
|
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
|
||||||
{
|
{
|
||||||
var beatmap = new Beatmap();
|
var beatmap = new Beatmap();
|
||||||
beatmap.HitObjects.Add(new HitCircle());
|
beatmap.HitObjects.Add(new HitCircle { StartTime = currentBeatmapDuration });
|
||||||
return beatmap;
|
return beatmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +209,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
private event Func<HealthProcessor, JudgementResult, bool> failConditions;
|
private event Func<HealthProcessor, JudgementResult, bool> failConditions;
|
||||||
|
|
||||||
public OutroPlayer(Func<HealthProcessor, JudgementResult, bool> failConditions, bool showResults = true)
|
public OutroPlayer(Func<HealthProcessor, JudgementResult, bool> failConditions, bool showResults = true)
|
||||||
: base(false, showResults)
|
: base(showResults: showResults)
|
||||||
{
|
{
|
||||||
this.failConditions = failConditions;
|
this.failConditions = failConditions;
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestEditDefaultSkin()
|
public void TestEditDefaultSkin()
|
||||||
{
|
{
|
||||||
AddAssert("is default skin", () => skinManager.CurrentSkinInfo.Value.ID == SkinInfo.TRIANGLES_SKIN);
|
AddAssert("is default skin", () => skinManager.CurrentSkinInfo.Value.ID == SkinInfo.ARGON_SKIN);
|
||||||
|
|
||||||
AddStep("open settings", () => { Game.Settings.Show(); });
|
AddStep("open settings", () => { Game.Settings.Show(); });
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
AddStep("open skin editor", () => skinEditor.Show());
|
AddStep("open skin editor", () => skinEditor.Show());
|
||||||
|
|
||||||
// Until step required as the skin editor may take time to load (and an extra scheduled frame for the mutable part).
|
// Until step required as the skin editor may take time to load (and an extra scheduled frame for the mutable part).
|
||||||
AddUntilStep("is modified default skin", () => skinManager.CurrentSkinInfo.Value.ID != SkinInfo.TRIANGLES_SKIN);
|
AddUntilStep("is modified default skin", () => skinManager.CurrentSkinInfo.Value.ID != SkinInfo.ARGON_SKIN);
|
||||||
AddAssert("is not protected", () => skinManager.CurrentSkinInfo.Value.PerformRead(s => !s.Protected));
|
AddAssert("is not protected", () => skinManager.CurrentSkinInfo.Value.PerformRead(s => !s.Protected));
|
||||||
|
|
||||||
AddUntilStep("export button enabled", () => Game.Settings.ChildrenOfType<SkinSection.ExportSkinButton>().SingleOrDefault()?.Enabled.Value == true);
|
AddUntilStep("export button enabled", () => Game.Settings.ChildrenOfType<SkinSection.ExportSkinButton>().SingleOrDefault()?.Enabled.Value == true);
|
||||||
|
@ -9,8 +9,10 @@ using NUnit.Framework;
|
|||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Catch;
|
||||||
using osu.Game.Rulesets.Mania;
|
using osu.Game.Rulesets.Mania;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
@ -92,6 +94,31 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
returnToMenu();
|
returnToMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestFromSongSelectWithFilter([Values] ScorePresentType type)
|
||||||
|
{
|
||||||
|
AddStep("enter song select", () => Game.ChildrenOfType<ButtonSystem>().Single().OnSolo.Invoke());
|
||||||
|
AddUntilStep("song select is current", () => Game.ScreenStack.CurrentScreen is PlaySongSelect songSelect && songSelect.BeatmapSetsLoaded);
|
||||||
|
|
||||||
|
AddStep("filter to nothing", () => ((PlaySongSelect)Game.ScreenStack.CurrentScreen).FilterControl.CurrentTextSearch.Value = "fdsajkl;fgewq");
|
||||||
|
AddUntilStep("wait for no results", () => Beatmap.IsDefault);
|
||||||
|
|
||||||
|
var firstImport = importScore(1, new CatchRuleset().RulesetInfo);
|
||||||
|
presentAndConfirm(firstImport, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestFromSongSelectWithConvertRulesetChange([Values] ScorePresentType type)
|
||||||
|
{
|
||||||
|
AddStep("enter song select", () => Game.ChildrenOfType<ButtonSystem>().Single().OnSolo.Invoke());
|
||||||
|
AddUntilStep("song select is current", () => Game.ScreenStack.CurrentScreen is PlaySongSelect songSelect && songSelect.BeatmapSetsLoaded);
|
||||||
|
|
||||||
|
AddStep("set convert to false", () => Game.LocalConfig.SetValue(OsuSetting.ShowConvertedBeatmaps, false));
|
||||||
|
|
||||||
|
var firstImport = importScore(1, new CatchRuleset().RulesetInfo);
|
||||||
|
presentAndConfirm(firstImport, type);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestFromSongSelect([Values] ScorePresentType type)
|
public void TestFromSongSelect([Values] ScorePresentType type)
|
||||||
{
|
{
|
||||||
|
@ -29,11 +29,7 @@ namespace osu.Game.Tests.Visual.Settings
|
|||||||
{
|
{
|
||||||
Child = textBox = new SettingsTextBox
|
Child = textBox = new SettingsTextBox
|
||||||
{
|
{
|
||||||
Current = new Bindable<string>
|
Current = new Bindable<string>("test")
|
||||||
{
|
|
||||||
Default = "test",
|
|
||||||
Value = "test"
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
AddUntilStep("wait for loaded", () => textBox.IsLoaded);
|
AddUntilStep("wait for loaded", () => textBox.IsLoaded);
|
||||||
@ -59,11 +55,7 @@ namespace osu.Game.Tests.Visual.Settings
|
|||||||
{
|
{
|
||||||
Child = textBox = new SettingsTextBox
|
Child = textBox = new SettingsTextBox
|
||||||
{
|
{
|
||||||
Current = new Bindable<string>
|
Current = new Bindable<string>("test")
|
||||||
{
|
|
||||||
Default = "test",
|
|
||||||
Value = "test"
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
AddUntilStep("wait for loaded", () => textBox.IsLoaded);
|
AddUntilStep("wait for loaded", () => textBox.IsLoaded);
|
||||||
|
@ -67,11 +67,7 @@ namespace osu.Game.Tests.Visual.Settings
|
|||||||
};
|
};
|
||||||
|
|
||||||
[SettingSource("Sample number textbox", "Textbox number entry", SettingControlType = typeof(SettingsNumberBox))]
|
[SettingSource("Sample number textbox", "Textbox number entry", SettingControlType = typeof(SettingsNumberBox))]
|
||||||
public Bindable<int?> IntTextBoxBindable { get; } = new Bindable<int?>
|
public Bindable<int?> IntTextBoxBindable { get; } = new Bindable<int?>();
|
||||||
{
|
|
||||||
Default = null,
|
|
||||||
Value = null
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum TestEnum
|
private enum TestEnum
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -36,10 +34,9 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
[Cached(typeof(IDialogOverlay))]
|
[Cached(typeof(IDialogOverlay))]
|
||||||
private readonly DialogOverlay dialogOverlay;
|
private readonly DialogOverlay dialogOverlay;
|
||||||
|
|
||||||
private ScoreManager scoreManager;
|
private ScoreManager scoreManager = null!;
|
||||||
|
private RulesetStore rulesetStore = null!;
|
||||||
private RulesetStore rulesetStore;
|
private BeatmapManager beatmapManager = null!;
|
||||||
private BeatmapManager beatmapManager;
|
|
||||||
|
|
||||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||||
{
|
{
|
||||||
@ -74,7 +71,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestLocalScoresDisplay()
|
public void TestLocalScoresDisplay()
|
||||||
{
|
{
|
||||||
BeatmapInfo beatmapInfo = null;
|
BeatmapInfo beatmapInfo = null!;
|
||||||
|
|
||||||
AddStep(@"Set scope", () => leaderboard.Scope = BeatmapLeaderboardScope.Local);
|
AddStep(@"Set scope", () => leaderboard.Scope = BeatmapLeaderboardScope.Local);
|
||||||
|
|
||||||
@ -387,7 +384,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
private class FailableLeaderboard : BeatmapLeaderboard
|
private class FailableLeaderboard : BeatmapLeaderboard
|
||||||
{
|
{
|
||||||
public new void SetErrorState(LeaderboardState state) => base.SetErrorState(state);
|
public new void SetErrorState(LeaderboardState state) => base.SetErrorState(state);
|
||||||
public new void SetScores(IEnumerable<ScoreInfo> scores, ScoreInfo userScore = default) => base.SetScores(scores, userScore);
|
public new void SetScores(IEnumerable<ScoreInfo>? scores, ScoreInfo? userScore = null) => base.SetScores(scores, userScore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,7 +163,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
InputManager.PressButton(MouseButton.Left);
|
InputManager.PressButton(MouseButton.Left);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for fetch", () => leaderboard.Scores != null);
|
AddUntilStep("wait for fetch", () => leaderboard.Scores.Any());
|
||||||
AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineID != scoreBeingDeleted.OnlineID));
|
AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineID != scoreBeingDeleted.OnlineID));
|
||||||
|
|
||||||
// "Clean up"
|
// "Clean up"
|
||||||
@ -174,7 +174,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
public void TestDeleteViaDatabase()
|
public void TestDeleteViaDatabase()
|
||||||
{
|
{
|
||||||
AddStep("delete top score", () => scoreManager.Delete(importedScores[0]));
|
AddStep("delete top score", () => scoreManager.Delete(importedScores[0]));
|
||||||
AddUntilStep("wait for fetch", () => leaderboard.Scores != null);
|
AddUntilStep("wait for fetch", () => leaderboard.Scores.Any());
|
||||||
AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineID != importedScores[0].OnlineID));
|
AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineID != importedScores[0].OnlineID));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,9 +107,9 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
AddStep("start drag", () =>
|
AddStep("start drag", () =>
|
||||||
{
|
{
|
||||||
InputManager.MoveMouseTo(notification.ChildrenOfType<Notification>().Single());
|
InputManager.MoveMouseTo(notificationOverlay.ChildrenOfType<Notification>().Single());
|
||||||
InputManager.PressButton(MouseButton.Left);
|
InputManager.PressButton(MouseButton.Left);
|
||||||
InputManager.MoveMouseTo(notification.ChildrenOfType<Notification>().Single().ScreenSpaceDrawQuad.Centre + new Vector2(-500, 0));
|
InputManager.MoveMouseTo(notificationOverlay.ChildrenOfType<Notification>().Single().ScreenSpaceDrawQuad.Centre + new Vector2(-500, 0));
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("fling away", () =>
|
AddStep("fling away", () =>
|
||||||
@ -123,6 +123,45 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
AddAssert("unread count zero", () => notificationOverlay.UnreadCount.Value == 0);
|
AddAssert("unread count zero", () => notificationOverlay.UnreadCount.Value == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestProgressNotificationCantBeFlung()
|
||||||
|
{
|
||||||
|
bool activated = false;
|
||||||
|
ProgressNotification notification = null!;
|
||||||
|
|
||||||
|
AddStep("post", () =>
|
||||||
|
{
|
||||||
|
activated = false;
|
||||||
|
notificationOverlay.Post(notification = new ProgressNotification
|
||||||
|
{
|
||||||
|
Text = @"Uploading to BSS...",
|
||||||
|
CompletionText = "Uploaded to BSS!",
|
||||||
|
Activated = () => activated = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
progressingNotifications.Add(notification);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("start drag", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(notificationOverlay.ChildrenOfType<Notification>().Single());
|
||||||
|
InputManager.PressButton(MouseButton.Left);
|
||||||
|
InputManager.MoveMouseTo(notificationOverlay.ChildrenOfType<Notification>().Single().ScreenSpaceDrawQuad.Centre + new Vector2(-500, 0));
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("attempt fling", () =>
|
||||||
|
{
|
||||||
|
InputManager.ReleaseButton(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("was not closed", () => !notification.WasClosed);
|
||||||
|
AddUntilStep("was not cancelled", () => notification.State == ProgressNotificationState.Active);
|
||||||
|
AddAssert("was not activated", () => !activated);
|
||||||
|
AddStep("reset mouse position", () => InputManager.MoveMouseTo(Vector2.Zero));
|
||||||
|
|
||||||
|
AddUntilStep("was completed", () => notification.State == ProgressNotificationState.Completed);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestDismissWithoutActivationCloseButton()
|
public void TestDismissWithoutActivationCloseButton()
|
||||||
{
|
{
|
||||||
@ -465,7 +504,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
progressingNotifications.RemoveAll(n => n.State == ProgressNotificationState.Completed);
|
progressingNotifications.RemoveAll(n => n.State == ProgressNotificationState.Completed && n.WasClosed);
|
||||||
|
|
||||||
if (progressingNotifications.Count(n => n.State == ProgressNotificationState.Active) < 3)
|
if (progressingNotifications.Count(n => n.State == ProgressNotificationState.Active) < 3)
|
||||||
{
|
{
|
||||||
|
@ -24,7 +24,6 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
public readonly BindableDouble SliderVelocityBindable = new BindableDouble(1)
|
public readonly BindableDouble SliderVelocityBindable = new BindableDouble(1)
|
||||||
{
|
{
|
||||||
Precision = 0.01,
|
Precision = 0.01,
|
||||||
Default = 1,
|
|
||||||
MinValue = 0.1,
|
MinValue = 0.1,
|
||||||
MaxValue = 10
|
MaxValue = 10
|
||||||
};
|
};
|
||||||
|
@ -28,7 +28,6 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
public readonly BindableDouble ScrollSpeedBindable = new BindableDouble(1)
|
public readonly BindableDouble ScrollSpeedBindable = new BindableDouble(1)
|
||||||
{
|
{
|
||||||
Precision = 0.01,
|
Precision = 0.01,
|
||||||
Default = 1,
|
|
||||||
MinValue = 0.01,
|
MinValue = 0.01,
|
||||||
MaxValue = 10
|
MaxValue = 10
|
||||||
};
|
};
|
||||||
|
@ -45,7 +45,6 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
{
|
{
|
||||||
MinValue = 0,
|
MinValue = 0,
|
||||||
MaxValue = 100,
|
MaxValue = 100,
|
||||||
Default = 100
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -49,7 +49,6 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly BindableDouble BeatLengthBindable = new BindableDouble(DEFAULT_BEAT_LENGTH)
|
public readonly BindableDouble BeatLengthBindable = new BindableDouble(DEFAULT_BEAT_LENGTH)
|
||||||
{
|
{
|
||||||
Default = DEFAULT_BEAT_LENGTH,
|
|
||||||
MinValue = 6,
|
MinValue = 6,
|
||||||
MaxValue = 60000
|
MaxValue = 60000
|
||||||
};
|
};
|
||||||
|
@ -39,7 +39,7 @@ namespace osu.Game.Configuration
|
|||||||
{
|
{
|
||||||
// UI/selection defaults
|
// UI/selection defaults
|
||||||
SetDefault(OsuSetting.Ruleset, string.Empty);
|
SetDefault(OsuSetting.Ruleset, string.Empty);
|
||||||
SetDefault(OsuSetting.Skin, SkinInfo.TRIANGLES_SKIN.ToString());
|
SetDefault(OsuSetting.Skin, SkinInfo.ARGON_SKIN.ToString());
|
||||||
|
|
||||||
SetDefault(OsuSetting.BeatmapDetailTab, PlayBeatmapDetailArea.TabType.Details);
|
SetDefault(OsuSetting.BeatmapDetailTab, PlayBeatmapDetailArea.TabType.Details);
|
||||||
SetDefault(OsuSetting.BeatmapDetailModsFilter, false);
|
SetDefault(OsuSetting.BeatmapDetailModsFilter, false);
|
||||||
@ -131,6 +131,7 @@ namespace osu.Game.Configuration
|
|||||||
SetDefault(OsuSetting.ShowHealthDisplayWhenCantFail, true);
|
SetDefault(OsuSetting.ShowHealthDisplayWhenCantFail, true);
|
||||||
SetDefault(OsuSetting.FadePlayfieldWhenHealthLow, true);
|
SetDefault(OsuSetting.FadePlayfieldWhenHealthLow, true);
|
||||||
SetDefault(OsuSetting.KeyOverlay, false);
|
SetDefault(OsuSetting.KeyOverlay, false);
|
||||||
|
SetDefault(OsuSetting.GameplayLeaderboard, true);
|
||||||
SetDefault(OsuSetting.AlwaysPlayFirstComboBreak, true);
|
SetDefault(OsuSetting.AlwaysPlayFirstComboBreak, true);
|
||||||
|
|
||||||
SetDefault(OsuSetting.FloatingComments, false);
|
SetDefault(OsuSetting.FloatingComments, false);
|
||||||
@ -294,6 +295,7 @@ namespace osu.Game.Configuration
|
|||||||
LightenDuringBreaks,
|
LightenDuringBreaks,
|
||||||
ShowStoryboard,
|
ShowStoryboard,
|
||||||
KeyOverlay,
|
KeyOverlay,
|
||||||
|
GameplayLeaderboard,
|
||||||
PositionalHitsounds,
|
PositionalHitsounds,
|
||||||
PositionalHitsoundsLevel,
|
PositionalHitsoundsLevel,
|
||||||
AlwaysPlayFirstComboBreak,
|
AlwaysPlayFirstComboBreak,
|
||||||
|
@ -89,6 +89,11 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString Collections => new TranslatableString(getKey(@"collections"), @"Collections");
|
public static LocalisableString Collections => new TranslatableString(getKey(@"collections"), @"Collections");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Mod presets"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString ModPresets => new TranslatableString(getKey(@"mod_presets"), @"Mod presets");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Name"
|
/// "Name"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -44,11 +44,6 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString ClearAllCaches => new TranslatableString(getKey(@"clear_all_caches"), @"Clear all caches");
|
public static LocalisableString ClearAllCaches => new TranslatableString(getKey(@"clear_all_caches"), @"Clear all caches");
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// "Compact realm"
|
|
||||||
/// </summary>
|
|
||||||
public static LocalisableString CompactRealm => new TranslatableString(getKey(@"compact_realm"), @"Compact realm");
|
|
||||||
|
|
||||||
private static string getKey(string key) => $"{prefix}:{key}";
|
private static string getKey(string key) => $"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,11 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString AlwaysShowKeyOverlay => new TranslatableString(getKey(@"key_overlay"), @"Always show key overlay");
|
public static LocalisableString AlwaysShowKeyOverlay => new TranslatableString(getKey(@"key_overlay"), @"Always show key overlay");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Always show gameplay leaderboard"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString AlwaysShowGameplayLeaderboard => new TranslatableString(getKey(@"gameplay_leaderboard"), @"Always show gameplay leaderboard");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Always play first combo break sound"
|
/// "Always play first combo break sound"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -64,6 +64,11 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString RunSetupWizard => new TranslatableString(getKey(@"run_setup_wizard"), @"Run setup wizard");
|
public static LocalisableString RunSetupWizard => new TranslatableString(getKey(@"run_setup_wizard"), @"Run setup wizard");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "You are running the latest release ({0})"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString RunningLatestRelease(string version) => new TranslatableString(getKey(@"running_latest_release"), @"You are running the latest release ({0})", version);
|
||||||
|
|
||||||
private static string getKey(string key) => $"{prefix}:{key}";
|
private static string getKey(string key) => $"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,41 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString SelectDirectory => new TranslatableString(getKey(@"select_directory"), @"Select directory");
|
public static LocalisableString SelectDirectory => new TranslatableString(getKey(@"select_directory"), @"Select directory");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Migration in progress"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString MigrationInProgress => new TranslatableString(getKey(@"migration_in_progress"), @"Migration in progress");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "This could take a few minutes depending on the speed of your disk(s)."
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString MigrationDescription => new TranslatableString(getKey(@"migration_description"), @"This could take a few minutes depending on the speed of your disk(s).");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Please avoid interacting with the game!"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString ProhibitedInteractDuringMigration => new TranslatableString(getKey(@"prohibited_interact_during_migration"), @"Please avoid interacting with the game!");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Some files couldn't be cleaned up during migration. Clicking this notification will open the folder so you can manually clean things up."
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString FailedCleanupNotification => new TranslatableString(getKey(@"failed_cleanup_notification"), @"Some files couldn't be cleaned up during migration. Clicking this notification will open the folder so you can manually clean things up.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Please select a new location"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString SelectNewLocation => new TranslatableString(getKey(@"select_new_location"), @"Please select a new location");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "The target directory already seems to have an osu! install. Use that data instead?"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString TargetDirectoryAlreadyInstalledOsu => new TranslatableString(getKey(@"target_directory_already_installed_osu"), @"The target directory already seems to have an osu! install. Use that data instead?");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "To complete this operation, osu! will close. Please open it again to use the new data location."
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString RestartAndReOpenRequiredForCompletion => new TranslatableString(getKey(@"restart_and_re_open_required_for_completion"), @"To complete this operation, osu! will close. Please open it again to use the new data location.");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Import beatmaps from stable"
|
/// "Import beatmaps from stable"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -84,6 +119,26 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString RestoreAllRecentlyDeletedModPresets => new TranslatableString(getKey(@"restore_all_recently_deleted_mod_presets"), @"Restore all recently deleted mod presets");
|
public static LocalisableString RestoreAllRecentlyDeletedModPresets => new TranslatableString(getKey(@"restore_all_recently_deleted_mod_presets"), @"Restore all recently deleted mod presets");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Deleted all collections!"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString DeletedAllCollections => new TranslatableString(getKey(@"deleted_all_collections"), @"Deleted all collections!");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Deleted all mod presets!"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString DeletedAllModPresets => new TranslatableString(getKey(@"deleted_all_mod_presets"), @"Deleted all mod presets!");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Restored all deleted mod presets!"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString RestoredAllDeletedModPresets => new TranslatableString(getKey(@"restored_all_deleted_mod_presets"), @"Restored all deleted mod presets!");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Please select your osu!stable install location"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString StableDirectorySelectHeader => new TranslatableString(getKey(@"stable_directory_select_header"), @"Please select your osu!stable install location");
|
||||||
|
|
||||||
private static string getKey(string key) => $"{prefix}:{key}";
|
private static string getKey(string key) => $"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,11 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString NoTabletDetected => new TranslatableString(getKey(@"no_tablet_detected"), @"No tablet detected!");
|
public static LocalisableString NoTabletDetected => new TranslatableString(getKey(@"no_tablet_detected"), @"No tablet detected!");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "If your tablet is not detected, please read [this FAQ]({0}) for troubleshooting steps."
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString NoTabletDetectedDescription(string url) => new TranslatableString(getKey(@"no_tablet_detected_description"), @"If your tablet is not detected, please read [this FAQ]({0}) for troubleshooting steps.", url);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Reset to full area"
|
/// "Reset to full area"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -9,27 +9,25 @@ namespace osu.Game.Online.API.Requests
|
|||||||
{
|
{
|
||||||
public class GetBeatmapRequest : APIRequest<APIBeatmap>
|
public class GetBeatmapRequest : APIRequest<APIBeatmap>
|
||||||
{
|
{
|
||||||
private readonly IBeatmapInfo beatmapInfo;
|
public readonly IBeatmapInfo BeatmapInfo;
|
||||||
|
public readonly string Filename;
|
||||||
private readonly string filename;
|
|
||||||
|
|
||||||
public GetBeatmapRequest(IBeatmapInfo beatmapInfo)
|
public GetBeatmapRequest(IBeatmapInfo beatmapInfo)
|
||||||
{
|
{
|
||||||
this.beatmapInfo = beatmapInfo;
|
BeatmapInfo = beatmapInfo;
|
||||||
|
Filename = (beatmapInfo as BeatmapInfo)?.Path ?? string.Empty;
|
||||||
filename = (beatmapInfo as BeatmapInfo)?.Path ?? string.Empty;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override WebRequest CreateWebRequest()
|
protected override WebRequest CreateWebRequest()
|
||||||
{
|
{
|
||||||
var request = base.CreateWebRequest();
|
var request = base.CreateWebRequest();
|
||||||
|
|
||||||
if (beatmapInfo.OnlineID > 0)
|
if (BeatmapInfo.OnlineID > 0)
|
||||||
request.AddParameter(@"id", beatmapInfo.OnlineID.ToString());
|
request.AddParameter(@"id", BeatmapInfo.OnlineID.ToString());
|
||||||
if (!string.IsNullOrEmpty(beatmapInfo.MD5Hash))
|
if (!string.IsNullOrEmpty(BeatmapInfo.MD5Hash))
|
||||||
request.AddParameter(@"checksum", beatmapInfo.MD5Hash);
|
request.AddParameter(@"checksum", BeatmapInfo.MD5Hash);
|
||||||
if (!string.IsNullOrEmpty(filename))
|
if (!string.IsNullOrEmpty(Filename))
|
||||||
request.AddParameter(@"filename", filename);
|
request.AddParameter(@"filename", Filename);
|
||||||
|
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
@ -228,7 +228,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
[JsonProperty(@"rank_history")]
|
[JsonProperty(@"rank_history")]
|
||||||
private APIRankHistory rankHistory
|
private APIRankHistory rankHistory
|
||||||
{
|
{
|
||||||
set => statistics.RankHistory = value;
|
set => Statistics.RankHistory = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonProperty("badges")]
|
[JsonProperty("badges")]
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using JetBrains.Annotations;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Development;
|
using osu.Framework.Development;
|
||||||
@ -54,23 +51,23 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
private readonly Container placeholderContainer;
|
private readonly Container placeholderContainer;
|
||||||
private readonly UserTopScoreContainer<TScoreInfo> userScoreContainer;
|
private readonly UserTopScoreContainer<TScoreInfo> userScoreContainer;
|
||||||
|
|
||||||
private FillFlowContainer<LeaderboardScore> scoreFlowContainer;
|
private FillFlowContainer<LeaderboardScore>? scoreFlowContainer;
|
||||||
|
|
||||||
private readonly LoadingSpinner loading;
|
private readonly LoadingSpinner loading;
|
||||||
|
|
||||||
private CancellationTokenSource currentFetchCancellationSource;
|
private CancellationTokenSource? currentFetchCancellationSource;
|
||||||
private CancellationTokenSource currentScoresAsyncLoadCancellationSource;
|
private CancellationTokenSource? currentScoresAsyncLoadCancellationSource;
|
||||||
|
|
||||||
private APIRequest fetchScoresRequest;
|
private APIRequest? fetchScoresRequest;
|
||||||
|
|
||||||
private LeaderboardState state;
|
private LeaderboardState state;
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private IAPIProvider api { get; set; }
|
private IAPIProvider? api { get; set; }
|
||||||
|
|
||||||
private readonly IBindable<APIState> apiState = new Bindable<APIState>();
|
private readonly IBindable<APIState> apiState = new Bindable<APIState>();
|
||||||
|
|
||||||
private TScope scope;
|
private TScope scope = default!;
|
||||||
|
|
||||||
public TScope Scope
|
public TScope Scope
|
||||||
{
|
{
|
||||||
@ -179,16 +176,21 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="scores">The scores to display.</param>
|
/// <param name="scores">The scores to display.</param>
|
||||||
/// <param name="userScore">The user top score, if any.</param>
|
/// <param name="userScore">The user top score, if any.</param>
|
||||||
protected void SetScores(IEnumerable<TScoreInfo> scores, TScoreInfo userScore = default)
|
protected void SetScores(IEnumerable<TScoreInfo>? scores, TScoreInfo? userScore = default)
|
||||||
{
|
{
|
||||||
this.scores.Clear();
|
this.scores.Clear();
|
||||||
if (scores != null)
|
if (scores != null)
|
||||||
this.scores.AddRange(scores);
|
this.scores.AddRange(scores);
|
||||||
|
|
||||||
// Schedule needs to be non-delayed here for the weird logic in refetchScores to work.
|
// Non-delayed schedule may potentially run inline (due to IsMainThread check passing) after leaderboard is disposed.
|
||||||
// If it is removed, the placeholder will be incorrectly updated to "no scores" rather than "retrieving".
|
// This is guarded against in BeatmapLeaderboard via web request cancellation, but let's be extra safe.
|
||||||
// This whole flow should be refactored in the future.
|
if (!IsDisposed)
|
||||||
Scheduler.Add(applyNewScores, false);
|
{
|
||||||
|
// Schedule needs to be non-delayed here for the weird logic in refetchScores to work.
|
||||||
|
// If it is removed, the placeholder will be incorrectly updated to "no scores" rather than "retrieving".
|
||||||
|
// This whole flow should be refactored in the future.
|
||||||
|
Scheduler.Add(applyNewScores, false);
|
||||||
|
}
|
||||||
|
|
||||||
void applyNewScores()
|
void applyNewScores()
|
||||||
{
|
{
|
||||||
@ -208,8 +210,7 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns>An <see cref="APIRequest"/> responsible for the fetch operation. This will be queued and performed automatically.</returns>
|
/// <returns>An <see cref="APIRequest"/> responsible for the fetch operation. This will be queued and performed automatically.</returns>
|
||||||
[CanBeNull]
|
protected abstract APIRequest? FetchScores(CancellationToken cancellationToken);
|
||||||
protected abstract APIRequest FetchScores(CancellationToken cancellationToken);
|
|
||||||
|
|
||||||
protected abstract LeaderboardScore CreateDrawableScore(TScoreInfo model, int index);
|
protected abstract LeaderboardScore CreateDrawableScore(TScoreInfo model, int index);
|
||||||
|
|
||||||
@ -293,7 +294,7 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
|
|
||||||
#region Placeholder handling
|
#region Placeholder handling
|
||||||
|
|
||||||
private Placeholder placeholder;
|
private Placeholder? placeholder;
|
||||||
|
|
||||||
private void setState(LeaderboardState state)
|
private void setState(LeaderboardState state)
|
||||||
{
|
{
|
||||||
@ -320,7 +321,7 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
placeholder.FadeInFromZero(fade_duration, Easing.OutQuint);
|
placeholder.FadeInFromZero(fade_duration, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Placeholder getPlaceholderFor(LeaderboardState state)
|
private Placeholder? getPlaceholderFor(LeaderboardState state)
|
||||||
{
|
{
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
@ -18,13 +16,15 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
{
|
{
|
||||||
private const int duration = 500;
|
private const int duration = 500;
|
||||||
|
|
||||||
public Bindable<TScoreInfo> Score = new Bindable<TScoreInfo>();
|
public Bindable<TScoreInfo?> Score = new Bindable<TScoreInfo?>();
|
||||||
|
|
||||||
private readonly Container scoreContainer;
|
private readonly Container scoreContainer;
|
||||||
private readonly Func<TScoreInfo, LeaderboardScore> createScoreDelegate;
|
private readonly Func<TScoreInfo, LeaderboardScore> createScoreDelegate;
|
||||||
|
|
||||||
protected override bool StartHidden => true;
|
protected override bool StartHidden => true;
|
||||||
|
|
||||||
|
private CancellationTokenSource? loadScoreCancellation;
|
||||||
|
|
||||||
public UserTopScoreContainer(Func<TScoreInfo, LeaderboardScore> createScoreDelegate)
|
public UserTopScoreContainer(Func<TScoreInfo, LeaderboardScore> createScoreDelegate)
|
||||||
{
|
{
|
||||||
this.createScoreDelegate = createScoreDelegate;
|
this.createScoreDelegate = createScoreDelegate;
|
||||||
@ -65,9 +65,7 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
Score.BindValueChanged(onScoreChanged);
|
Score.BindValueChanged(onScoreChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CancellationTokenSource loadScoreCancellation;
|
private void onScoreChanged(ValueChangedEvent<TScoreInfo?> score)
|
||||||
|
|
||||||
private void onScoreChanged(ValueChangedEvent<TScoreInfo> score)
|
|
||||||
{
|
{
|
||||||
var newScore = score.NewValue;
|
var newScore = score.NewValue;
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
using Microsoft.AspNetCore.SignalR.Client;
|
using Microsoft.AspNetCore.SignalR.Client;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
@ -58,7 +58,7 @@ namespace osu.Game.Online.Spectator
|
|||||||
{
|
{
|
||||||
await connection.InvokeAsync(nameof(ISpectatorServer.BeginPlaySession), state);
|
await connection.InvokeAsync(nameof(ISpectatorServer.BeginPlaySession), state);
|
||||||
}
|
}
|
||||||
catch (HubException exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
if (exception.GetHubExceptionMessage() == HubClientConnector.SERVER_SHUTDOWN_MESSAGE)
|
if (exception.GetHubExceptionMessage() == HubClientConnector.SERVER_SHUTDOWN_MESSAGE)
|
||||||
{
|
{
|
||||||
|
@ -561,9 +561,11 @@ namespace osu.Game
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This should be able to be performed from song select, but that is disabled for now
|
||||||
|
// due to the weird decoupled ruleset logic (which can cause a crash in certain filter scenarios).
|
||||||
PerformFromScreen(screen =>
|
PerformFromScreen(screen =>
|
||||||
{
|
{
|
||||||
Logger.Log($"{nameof(PresentScore)} updating beatmap ({databasedBeatmap}) and ruleset ({databasedScore.ScoreInfo.Ruleset} to match score");
|
Logger.Log($"{nameof(PresentScore)} updating beatmap ({databasedBeatmap}) and ruleset ({databasedScore.ScoreInfo.Ruleset}) to match score");
|
||||||
|
|
||||||
Ruleset.Value = databasedScore.ScoreInfo.Ruleset;
|
Ruleset.Value = databasedScore.ScoreInfo.Ruleset;
|
||||||
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap);
|
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap);
|
||||||
@ -578,7 +580,7 @@ namespace osu.Game
|
|||||||
screen.Push(new SoloResultsScreen(databasedScore.ScoreInfo, false));
|
screen.Push(new SoloResultsScreen(databasedScore.ScoreInfo, false));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}, validScreens: new[] { typeof(PlaySongSelect) });
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task Import(params ImportTask[] imports)
|
public override Task Import(params ImportTask[] imports)
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Resources.Localisation.Web;
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Dialog
|
namespace osu.Game.Overlays.Dialog
|
||||||
@ -20,7 +21,7 @@ namespace osu.Game.Overlays.Dialog
|
|||||||
/// <param name="message">The description of the action to be displayed to the user.</param>
|
/// <param name="message">The description of the action to be displayed to the user.</param>
|
||||||
/// <param name="onConfirm">An action to perform on confirmation.</param>
|
/// <param name="onConfirm">An action to perform on confirmation.</param>
|
||||||
/// <param name="onCancel">An optional action to perform on cancel.</param>
|
/// <param name="onCancel">An optional action to perform on cancel.</param>
|
||||||
public ConfirmDialog(string message, Action onConfirm, Action onCancel = null)
|
public ConfirmDialog(LocalisableString message, Action onConfirm, Action onCancel = null)
|
||||||
{
|
{
|
||||||
HeaderText = message;
|
HeaderText = message;
|
||||||
BodyText = "Last chance to turn back";
|
BodyText = "Last chance to turn back";
|
||||||
|
@ -123,7 +123,7 @@ namespace osu.Game.Overlays.FirstRunSetup
|
|||||||
beatmapSubscription?.Dispose();
|
beatmapSubscription?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void beatmapsChanged(IRealmCollection<BeatmapSetInfo> sender, ChangeSet? changes, Exception error)
|
private void beatmapsChanged(IRealmCollection<BeatmapSetInfo> sender, ChangeSet? changes, Exception error) => Schedule(() =>
|
||||||
{
|
{
|
||||||
currentlyLoadedBeatmaps.Text = FirstRunSetupBeatmapScreenStrings.CurrentlyLoadedBeatmaps(sender.Count);
|
currentlyLoadedBeatmaps.Text = FirstRunSetupBeatmapScreenStrings.CurrentlyLoadedBeatmaps(sender.Count);
|
||||||
|
|
||||||
@ -139,7 +139,7 @@ namespace osu.Game.Overlays.FirstRunSetup
|
|||||||
currentlyLoadedBeatmaps.ScaleTo(1.1f)
|
currentlyLoadedBeatmaps.ScaleTo(1.1f)
|
||||||
.ScaleTo(1, 1500, Easing.OutQuint);
|
.ScaleTo(1, 1500, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
private void downloadTutorial()
|
private void downloadTutorial()
|
||||||
{
|
{
|
||||||
|
@ -8,6 +8,7 @@ using System.Linq;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Extensions.EnumExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Effects;
|
using osu.Framework.Graphics.Effects;
|
||||||
@ -24,7 +25,7 @@ namespace osu.Game.Overlays.Music
|
|||||||
public class PlaylistOverlay : VisibilityContainer
|
public class PlaylistOverlay : VisibilityContainer
|
||||||
{
|
{
|
||||||
private const float transition_duration = 600;
|
private const float transition_duration = 600;
|
||||||
private const float playlist_height = 510;
|
public const float PLAYLIST_HEIGHT = 510;
|
||||||
|
|
||||||
private readonly BindableList<Live<BeatmapSetInfo>> beatmapSets = new BindableList<Live<BeatmapSetInfo>>();
|
private readonly BindableList<Live<BeatmapSetInfo>> beatmapSets = new BindableList<Live<BeatmapSetInfo>>();
|
||||||
|
|
||||||
@ -130,7 +131,7 @@ namespace osu.Game.Overlays.Music
|
|||||||
filter.Search.HoldFocus = true;
|
filter.Search.HoldFocus = true;
|
||||||
Schedule(() => filter.Search.TakeFocus());
|
Schedule(() => filter.Search.TakeFocus());
|
||||||
|
|
||||||
this.ResizeTo(new Vector2(1, playlist_height), transition_duration, Easing.OutQuint);
|
this.ResizeTo(new Vector2(1, RelativeSizeAxes.HasFlagFast(Axes.Y) ? 1f : PLAYLIST_HEIGHT), transition_duration, Easing.OutQuint);
|
||||||
this.FadeIn(transition_duration, Easing.OutQuint);
|
this.FadeIn(transition_duration, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,12 +58,11 @@ namespace osu.Game.Overlays
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private RealmAccess realm { get; set; }
|
private RealmAccess realm { get; set; }
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
protected override void LoadComplete()
|
||||||
private void load()
|
|
||||||
{
|
{
|
||||||
// Todo: These binds really shouldn't be here, but are unlikely to cause any issues for now.
|
base.LoadComplete();
|
||||||
// They are placed here for now since some tests rely on setting the beatmap _and_ their hierarchies inside their load(), which runs before the MusicController's load().
|
|
||||||
beatmap.BindValueChanged(beatmapChanged, true);
|
beatmap.BindValueChanged(b => changeBeatmap(b.NewValue), true);
|
||||||
mods.BindValueChanged(_ => ResetTrackAdjustments(), true);
|
mods.BindValueChanged(_ => ResetTrackAdjustments(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,8 +262,6 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private IQueryable<BeatmapSetInfo> getBeatmapSets() => realm.Realm.All<BeatmapSetInfo>().Where(s => !s.DeletePending);
|
private IQueryable<BeatmapSetInfo> getBeatmapSets() => realm.Realm.All<BeatmapSetInfo>().Where(s => !s.DeletePending);
|
||||||
|
|
||||||
private void beatmapChanged(ValueChangedEvent<WorkingBeatmap> beatmap) => changeBeatmap(beatmap.NewValue);
|
|
||||||
|
|
||||||
private void changeBeatmap(WorkingBeatmap newWorking)
|
private void changeBeatmap(WorkingBeatmap newWorking)
|
||||||
{
|
{
|
||||||
// This method can potentially be triggered multiple times as it is eagerly fired in next() / prev() to ensure correct execution order
|
// This method can potentially be triggered multiple times as it is eagerly fired in next() / prev() to ensure correct execution order
|
||||||
|
@ -113,9 +113,12 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
if (enabled)
|
if (enabled)
|
||||||
// we want a slight delay before toggling notifications on to avoid the user becoming overwhelmed.
|
// we want a slight delay before toggling notifications on to avoid the user becoming overwhelmed.
|
||||||
notificationsEnabler = Scheduler.AddDelayed(() => processingPosts = true, State.Value == Visibility.Visible ? 0 : 100);
|
notificationsEnabler = Scheduler.AddDelayed(() => processingPosts = true, State.Value == Visibility.Visible ? 0 : 250);
|
||||||
else
|
else
|
||||||
|
{
|
||||||
processingPosts = false;
|
processingPosts = false;
|
||||||
|
toastTray.FlushAllToasts();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
|
@ -68,6 +68,8 @@ namespace osu.Game.Overlays.Notifications
|
|||||||
|
|
||||||
public virtual bool Read { get; set; }
|
public virtual bool Read { get; set; }
|
||||||
|
|
||||||
|
protected virtual bool AllowFlingDismiss => true;
|
||||||
|
|
||||||
public new bool IsDragged => dragContainer.IsDragged;
|
public new bool IsDragged => dragContainer.IsDragged;
|
||||||
|
|
||||||
protected virtual IconUsage CloseButtonIcon => FontAwesome.Solid.Check;
|
protected virtual IconUsage CloseButtonIcon => FontAwesome.Solid.Check;
|
||||||
@ -315,7 +317,7 @@ namespace osu.Game.Overlays.Notifications
|
|||||||
|
|
||||||
protected override void OnDragEnd(DragEndEvent e)
|
protected override void OnDragEnd(DragEndEvent e)
|
||||||
{
|
{
|
||||||
if (Rotation < -10 || velocity.X < -0.3f)
|
if (notification.AllowFlingDismiss && (Rotation < -10 || velocity.X < -0.3f))
|
||||||
notification.Close(true);
|
notification.Close(true);
|
||||||
else if (X > 30 || velocity.X > 0.3f)
|
else if (X > 30 || velocity.X > 0.3f)
|
||||||
notification.ForwardToOverlay?.Invoke();
|
notification.ForwardToOverlay?.Invoke();
|
||||||
|
@ -25,6 +25,8 @@ namespace osu.Game.Overlays.Notifications
|
|||||||
|
|
||||||
public Func<bool>? CancelRequested { get; set; }
|
public Func<bool>? CancelRequested { get; set; }
|
||||||
|
|
||||||
|
protected override bool AllowFlingDismiss => false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The function to post completion notifications back to.
|
/// The function to post completion notifications back to.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -38,6 +38,7 @@ namespace osu.Game.Overlays
|
|||||||
private const float transition_length = 800;
|
private const float transition_length = 800;
|
||||||
private const float progress_height = 10;
|
private const float progress_height = 10;
|
||||||
private const float bottom_black_area_height = 55;
|
private const float bottom_black_area_height = 55;
|
||||||
|
private const float margin = 10;
|
||||||
|
|
||||||
private Drawable background;
|
private Drawable background;
|
||||||
private ProgressBar progressBar;
|
private ProgressBar progressBar;
|
||||||
@ -53,6 +54,7 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private Container dragContainer;
|
private Container dragContainer;
|
||||||
private Container playerContainer;
|
private Container playerContainer;
|
||||||
|
private Container playlistContainer;
|
||||||
|
|
||||||
protected override string PopInSampleName => "UI/now-playing-pop-in";
|
protected override string PopInSampleName => "UI/now-playing-pop-in";
|
||||||
protected override string PopOutSampleName => "UI/now-playing-pop-out";
|
protected override string PopOutSampleName => "UI/now-playing-pop-out";
|
||||||
@ -69,7 +71,7 @@ namespace osu.Game.Overlays
|
|||||||
public NowPlayingOverlay()
|
public NowPlayingOverlay()
|
||||||
{
|
{
|
||||||
Width = 400;
|
Width = 400;
|
||||||
Margin = new MarginPadding(10);
|
Margin = new MarginPadding(margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -82,7 +84,6 @@ namespace osu.Game.Overlays
|
|||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
playerContainer = new Container
|
playerContainer = new Container
|
||||||
@ -182,8 +183,13 @@ namespace osu.Game.Overlays
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
playlistContainer = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Y = player_height + margin,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,11 +199,10 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
LoadComponentAsync(playlist = new PlaylistOverlay
|
LoadComponentAsync(playlist = new PlaylistOverlay
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Y = player_height + 10,
|
|
||||||
}, _ =>
|
}, _ =>
|
||||||
{
|
{
|
||||||
dragContainer.Add(playlist);
|
playlistContainer.Add(playlist);
|
||||||
|
|
||||||
playlist.State.BindValueChanged(s => playlistButton.FadeColour(s.NewValue == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint), true);
|
playlist.State.BindValueChanged(s => playlistButton.FadeColour(s.NewValue == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint), true);
|
||||||
|
|
||||||
@ -242,7 +247,18 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
base.UpdateAfterChildren();
|
base.UpdateAfterChildren();
|
||||||
|
|
||||||
Height = dragContainer.Height;
|
playlistContainer.Height = MathF.Min(Parent.DrawHeight - margin * 3 - player_height, PlaylistOverlay.PLAYLIST_HEIGHT);
|
||||||
|
|
||||||
|
float height = player_height;
|
||||||
|
|
||||||
|
if (playlist != null)
|
||||||
|
{
|
||||||
|
height += playlist.DrawHeight;
|
||||||
|
if (playlist.State.Value == Visibility.Visible)
|
||||||
|
height += margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
Height = dragContainer.Height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
|
@ -35,7 +35,7 @@ namespace osu.Game.Overlays.Settings.Sections.DebugSettings
|
|||||||
},
|
},
|
||||||
new SettingsButton
|
new SettingsButton
|
||||||
{
|
{
|
||||||
Text = DebugSettingsStrings.CompactRealm,
|
Text = "Compact realm",
|
||||||
Action = () =>
|
Action = () =>
|
||||||
{
|
{
|
||||||
// Blocking operations implicitly causes a Compact().
|
// Blocking operations implicitly causes a Compact().
|
||||||
|
@ -38,6 +38,11 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
|||||||
Current = config.GetBindable<bool>(OsuSetting.KeyOverlay),
|
Current = config.GetBindable<bool>(OsuSetting.KeyOverlay),
|
||||||
Keywords = new[] { "counter" },
|
Keywords = new[] { "counter" },
|
||||||
},
|
},
|
||||||
|
new SettingsCheckbox
|
||||||
|
{
|
||||||
|
LabelText = GameplaySettingsStrings.AlwaysShowGameplayLeaderboard,
|
||||||
|
Current = config.GetBindable<bool>(OsuSetting.GameplayLeaderboard),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
{
|
{
|
||||||
notifications?.Post(new SimpleNotification
|
notifications?.Post(new SimpleNotification
|
||||||
{
|
{
|
||||||
Text = $"You are running the latest release ({game.Version})",
|
Text = GeneralSettingsStrings.RunningLatestRelease(game.Version),
|
||||||
Icon = FontAwesome.Solid.CheckCircle,
|
Icon = FontAwesome.Solid.CheckCircle,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -73,8 +73,8 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
|||||||
windowModes.BindTo(host.Window.SupportedWindowModes);
|
windowModes.BindTo(host.Window.SupportedWindowModes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (host.Window is WindowsWindow windowsWindow)
|
if (host.Renderer is IWindowsRenderer windowsRenderer)
|
||||||
fullscreenCapability.BindTo(windowsWindow.FullscreenCapability);
|
fullscreenCapability.BindTo(windowsRenderer.FullscreenCapability);
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
|
@ -72,7 +72,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours, LocalisationManager localisation)
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -110,11 +110,10 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows || RuntimeInfo.OS == RuntimeInfo.Platform.Linux)
|
if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows || RuntimeInfo.OS == RuntimeInfo.Platform.Linux)
|
||||||
{
|
{
|
||||||
t.NewLine();
|
t.NewLine();
|
||||||
t.AddText("If your tablet is not detected, please read ");
|
var formattedSource = MessageFormatter.FormatText(localisation.GetLocalisedBindableString(TabletSettingsStrings.NoTabletDetectedDescription(RuntimeInfo.OS == RuntimeInfo.Platform.Windows
|
||||||
t.AddLink("this FAQ", LinkAction.External, RuntimeInfo.OS == RuntimeInfo.Platform.Windows
|
|
||||||
? @"https://opentabletdriver.net/Wiki/FAQ/Windows"
|
? @"https://opentabletdriver.net/Wiki/FAQ/Windows"
|
||||||
: @"https://opentabletdriver.net/Wiki/FAQ/Linux");
|
: @"https://opentabletdriver.net/Wiki/FAQ/Linux")).Value);
|
||||||
t.AddText(" for troubleshooting steps.");
|
t.AddLinks(formattedSource.Text, formattedSource.Links);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
@ -215,21 +214,21 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
rotation.BindTo(tabletHandler.Rotation);
|
rotation.BindTo(tabletHandler.Rotation);
|
||||||
|
|
||||||
areaOffset.BindTo(tabletHandler.AreaOffset);
|
areaOffset.BindTo(tabletHandler.AreaOffset);
|
||||||
areaOffset.BindValueChanged(val =>
|
areaOffset.BindValueChanged(val => Schedule(() =>
|
||||||
{
|
{
|
||||||
offsetX.Value = val.NewValue.X;
|
offsetX.Value = val.NewValue.X;
|
||||||
offsetY.Value = val.NewValue.Y;
|
offsetY.Value = val.NewValue.Y;
|
||||||
}, true);
|
}), true);
|
||||||
|
|
||||||
offsetX.BindValueChanged(val => areaOffset.Value = new Vector2(val.NewValue, areaOffset.Value.Y));
|
offsetX.BindValueChanged(val => areaOffset.Value = new Vector2(val.NewValue, areaOffset.Value.Y));
|
||||||
offsetY.BindValueChanged(val => areaOffset.Value = new Vector2(areaOffset.Value.X, val.NewValue));
|
offsetY.BindValueChanged(val => areaOffset.Value = new Vector2(areaOffset.Value.X, val.NewValue));
|
||||||
|
|
||||||
areaSize.BindTo(tabletHandler.AreaSize);
|
areaSize.BindTo(tabletHandler.AreaSize);
|
||||||
areaSize.BindValueChanged(val =>
|
areaSize.BindValueChanged(val => Schedule(() =>
|
||||||
{
|
{
|
||||||
sizeX.Value = val.NewValue.X;
|
sizeX.Value = val.NewValue.X;
|
||||||
sizeY.Value = val.NewValue.Y;
|
sizeY.Value = val.NewValue.Y;
|
||||||
}, true);
|
}), true);
|
||||||
|
|
||||||
sizeX.BindValueChanged(val =>
|
sizeX.BindValueChanged(val =>
|
||||||
{
|
{
|
||||||
@ -255,7 +254,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
});
|
});
|
||||||
|
|
||||||
tablet.BindTo(tabletHandler.Tablet);
|
tablet.BindTo(tabletHandler.Tablet);
|
||||||
tablet.BindValueChanged(val =>
|
tablet.BindValueChanged(val => Schedule(() =>
|
||||||
{
|
{
|
||||||
Scheduler.AddOnce(updateVisibility);
|
Scheduler.AddOnce(updateVisibility);
|
||||||
|
|
||||||
@ -274,7 +273,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
sizeY.Default = sizeY.MaxValue = tab.Size.Y;
|
sizeY.Default = sizeY.MaxValue = tab.Size.Y;
|
||||||
|
|
||||||
areaSize.Default = new Vector2(sizeX.Default, sizeY.Default);
|
areaSize.Default = new Vector2(sizeX.Default, sizeY.Default);
|
||||||
}, true);
|
}), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateVisibility()
|
private void updateVisibility()
|
||||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
{
|
{
|
||||||
public class BeatmapSettings : SettingsSubsection
|
public class BeatmapSettings : SettingsSubsection
|
||||||
{
|
{
|
||||||
protected override LocalisableString Header => "Beatmaps";
|
protected override LocalisableString Header => CommonStrings.Beatmaps;
|
||||||
|
|
||||||
private SettingsButton importBeatmapsButton = null!;
|
private SettingsButton importBeatmapsButton = null!;
|
||||||
private SettingsButton deleteBeatmapsButton = null!;
|
private SettingsButton deleteBeatmapsButton = null!;
|
||||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
{
|
{
|
||||||
public class CollectionsSettings : SettingsSubsection
|
public class CollectionsSettings : SettingsSubsection
|
||||||
{
|
{
|
||||||
protected override LocalisableString Header => "Collections";
|
protected override LocalisableString Header => CommonStrings.Collections;
|
||||||
|
|
||||||
private SettingsButton importCollectionsButton = null!;
|
private SettingsButton importCollectionsButton = null!;
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
private void deleteAllCollections()
|
private void deleteAllCollections()
|
||||||
{
|
{
|
||||||
realm.Write(r => r.RemoveAll<BeatmapCollection>());
|
realm.Write(r => r.RemoveAll<BeatmapCollection>());
|
||||||
notificationOverlay?.Post(new ProgressCompletionNotification { Text = "Deleted all collections!" });
|
notificationOverlay?.Post(new ProgressCompletionNotification { Text = MaintenanceSettingsStrings.DeletedAllCollections });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ using osu.Framework.Screens;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Localisation;
|
||||||
using osu.Game.Overlays.Notifications;
|
using osu.Game.Overlays.Notifications;
|
||||||
using osu.Game.Screens;
|
using osu.Game.Screens;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -71,14 +72,14 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Text = "Migration in progress",
|
Text = MaintenanceSettingsStrings.MigrationInProgress,
|
||||||
Font = OsuFont.Default.With(size: 40)
|
Font = OsuFont.Default.With(size: 40)
|
||||||
},
|
},
|
||||||
new OsuSpriteText
|
new OsuSpriteText
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Text = "This could take a few minutes depending on the speed of your disk(s).",
|
Text = MaintenanceSettingsStrings.MigrationDescription,
|
||||||
Font = OsuFont.Default.With(size: 30)
|
Font = OsuFont.Default.With(size: 30)
|
||||||
},
|
},
|
||||||
new LoadingSpinner(true)
|
new LoadingSpinner(true)
|
||||||
@ -89,7 +90,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Text = "Please avoid interacting with the game!",
|
Text = MaintenanceSettingsStrings.ProhibitedInteractDuringMigration,
|
||||||
Font = OsuFont.Default.With(size: 30)
|
Font = OsuFont.Default.With(size: 30)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -111,7 +112,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
{
|
{
|
||||||
notifications.Post(new SimpleNotification
|
notifications.Post(new SimpleNotification
|
||||||
{
|
{
|
||||||
Text = "Some files couldn't be cleaned up during migration. Clicking this notification will open the folder so you can manually clean things up.",
|
Text = MaintenanceSettingsStrings.FailedCleanupNotification,
|
||||||
Activated = () =>
|
Activated = () =>
|
||||||
{
|
{
|
||||||
originalStorage.PresentExternally();
|
originalStorage.PresentExternally();
|
||||||
|
@ -12,6 +12,7 @@ using osu.Framework.Logging;
|
|||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
|
using osu.Game.Localisation;
|
||||||
using osu.Game.Overlays.Dialog;
|
using osu.Game.Overlays.Dialog;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||||
@ -35,7 +36,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
|
|
||||||
public override bool HideOverlaysOnEnter => true;
|
public override bool HideOverlaysOnEnter => true;
|
||||||
|
|
||||||
public override LocalisableString HeaderText => "Please select a new location";
|
public override LocalisableString HeaderText => MaintenanceSettingsStrings.SelectNewLocation;
|
||||||
|
|
||||||
protected override void OnSelection(DirectoryInfo directory)
|
protected override void OnSelection(DirectoryInfo directory)
|
||||||
{
|
{
|
||||||
@ -51,9 +52,9 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
// Quick test for whether there's already an osu! install at the target path.
|
// Quick test for whether there's already an osu! install at the target path.
|
||||||
if (fileInfos.Any(f => f.Name == OsuGameBase.CLIENT_DATABASE_FILENAME))
|
if (fileInfos.Any(f => f.Name == OsuGameBase.CLIENT_DATABASE_FILENAME))
|
||||||
{
|
{
|
||||||
dialogOverlay.Push(new ConfirmDialog("The target directory already seems to have an osu! install. Use that data instead?", () =>
|
dialogOverlay.Push(new ConfirmDialog(MaintenanceSettingsStrings.TargetDirectoryAlreadyInstalledOsu, () =>
|
||||||
{
|
{
|
||||||
dialogOverlay.Push(new ConfirmDialog("To complete this operation, osu! will close. Please open it again to use the new data location.", () =>
|
dialogOverlay.Push(new ConfirmDialog(MaintenanceSettingsStrings.RestartAndReOpenRequiredForCompletion, () =>
|
||||||
{
|
{
|
||||||
(storage as OsuStorage)?.ChangeDataPath(target.FullName);
|
(storage as OsuStorage)?.ChangeDataPath(target.FullName);
|
||||||
game.Exit();
|
game.Exit();
|
||||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
{
|
{
|
||||||
public class ModPresetSettings : SettingsSubsection
|
public class ModPresetSettings : SettingsSubsection
|
||||||
{
|
{
|
||||||
protected override LocalisableString Header => "Mod presets";
|
protected override LocalisableString Header => CommonStrings.ModPresets;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private RealmAccess realm { get; set; } = null!;
|
private RealmAccess realm { get; set; } = null!;
|
||||||
@ -64,7 +64,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
deleteAllButton.Enabled.Value = true;
|
deleteAllButton.Enabled.Value = true;
|
||||||
|
|
||||||
if (deletionTask.IsCompletedSuccessfully)
|
if (deletionTask.IsCompletedSuccessfully)
|
||||||
notificationOverlay?.Post(new ProgressCompletionNotification { Text = "Deleted all mod presets!" });
|
notificationOverlay?.Post(new ProgressCompletionNotification { Text = MaintenanceSettingsStrings.DeletedAllModPresets });
|
||||||
else if (deletionTask.IsFaulted)
|
else if (deletionTask.IsFaulted)
|
||||||
Logger.Error(deletionTask.Exception, "Failed to delete all mod presets");
|
Logger.Error(deletionTask.Exception, "Failed to delete all mod presets");
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
undeleteButton.Enabled.Value = true;
|
undeleteButton.Enabled.Value = true;
|
||||||
|
|
||||||
if (undeletionTask.IsCompletedSuccessfully)
|
if (undeletionTask.IsCompletedSuccessfully)
|
||||||
notificationOverlay?.Post(new ProgressCompletionNotification { Text = "Restored all deleted mod presets!" });
|
notificationOverlay?.Post(new ProgressCompletionNotification { Text = MaintenanceSettingsStrings.RestoredAllDeletedModPresets });
|
||||||
else if (undeletionTask.IsFaulted)
|
else if (undeletionTask.IsFaulted)
|
||||||
Logger.Error(undeletionTask.Exception, "Failed to restore mod presets");
|
Logger.Error(undeletionTask.Exception, "Failed to restore mod presets");
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
{
|
{
|
||||||
public class ScoreSettings : SettingsSubsection
|
public class ScoreSettings : SettingsSubsection
|
||||||
{
|
{
|
||||||
protected override LocalisableString Header => "Scores";
|
protected override LocalisableString Header => CommonStrings.Scores;
|
||||||
|
|
||||||
private SettingsButton importScoresButton = null!;
|
private SettingsButton importScoresButton = null!;
|
||||||
private SettingsButton deleteScoresButton = null!;
|
private SettingsButton deleteScoresButton = null!;
|
||||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
{
|
{
|
||||||
public class SkinSettings : SettingsSubsection
|
public class SkinSettings : SettingsSubsection
|
||||||
{
|
{
|
||||||
protected override LocalisableString Header => "Skins";
|
protected override LocalisableString Header => CommonStrings.Skins;
|
||||||
|
|
||||||
private SettingsButton importSkinsButton = null!;
|
private SettingsButton importSkinsButton = null!;
|
||||||
private SettingsButton deleteSkinsButton = null!;
|
private SettingsButton deleteSkinsButton = null!;
|
||||||
|
@ -58,6 +58,9 @@ namespace osu.Game.Rulesets.Configuration
|
|||||||
pendingWrites.Clear();
|
pendingWrites.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!changed.Any())
|
||||||
|
return true;
|
||||||
|
|
||||||
realm?.Write(r =>
|
realm?.Write(r =>
|
||||||
{
|
{
|
||||||
foreach (var c in changed)
|
foreach (var c in changed)
|
||||||
|
@ -36,32 +36,24 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
public override Type[] IncompatibleMods => new[] { typeof(ModRateAdjust), typeof(ModTimeRamp), typeof(ModAutoplay) };
|
public override Type[] IncompatibleMods => new[] { typeof(ModRateAdjust), typeof(ModTimeRamp), typeof(ModAutoplay) };
|
||||||
|
|
||||||
[SettingSource("Initial rate", "The starting speed of the track")]
|
[SettingSource("Initial rate", "The starting speed of the track")]
|
||||||
public BindableNumber<double> InitialRate { get; } = new BindableDouble
|
public BindableNumber<double> InitialRate { get; } = new BindableDouble(1)
|
||||||
{
|
{
|
||||||
MinValue = 0.5,
|
MinValue = 0.5,
|
||||||
MaxValue = 2,
|
MaxValue = 2,
|
||||||
Default = 1,
|
|
||||||
Value = 1,
|
|
||||||
Precision = 0.01
|
Precision = 0.01
|
||||||
};
|
};
|
||||||
|
|
||||||
[SettingSource("Adjust pitch", "Should pitch be adjusted with speed")]
|
[SettingSource("Adjust pitch", "Should pitch be adjusted with speed")]
|
||||||
public BindableBool AdjustPitch { get; } = new BindableBool
|
public BindableBool AdjustPitch { get; } = new BindableBool(true);
|
||||||
{
|
|
||||||
Default = true,
|
|
||||||
Value = true
|
|
||||||
};
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The instantaneous rate of the track.
|
/// The instantaneous rate of the track.
|
||||||
/// Every frame this mod will attempt to smoothly adjust this to meet <see cref="targetRate"/>.
|
/// Every frame this mod will attempt to smoothly adjust this to meet <see cref="targetRate"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public BindableNumber<double> SpeedChange { get; } = new BindableDouble
|
public BindableNumber<double> SpeedChange { get; } = new BindableDouble(1)
|
||||||
{
|
{
|
||||||
MinValue = min_allowable_rate,
|
MinValue = min_allowable_rate,
|
||||||
MaxValue = max_allowable_rate,
|
MaxValue = max_allowable_rate,
|
||||||
Default = 1,
|
|
||||||
Value = 1
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// The two constants below denote the maximum allowable range of rates that `SpeedChange` can take.
|
// The two constants below denote the maximum allowable range of rates that `SpeedChange` can take.
|
||||||
|
@ -18,12 +18,10 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
public override LocalisableString Description => "Zoooooooooom...";
|
public override LocalisableString Description => "Zoooooooooom...";
|
||||||
|
|
||||||
[SettingSource("Speed increase", "The actual increase to apply")]
|
[SettingSource("Speed increase", "The actual increase to apply")]
|
||||||
public override BindableNumber<double> SpeedChange { get; } = new BindableDouble
|
public override BindableNumber<double> SpeedChange { get; } = new BindableDouble(1.5)
|
||||||
{
|
{
|
||||||
MinValue = 1.01,
|
MinValue = 1.01,
|
||||||
MaxValue = 2,
|
MaxValue = 2,
|
||||||
Default = 1.5,
|
|
||||||
Value = 1.5,
|
|
||||||
Precision = 0.01,
|
Precision = 0.01,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,10 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
public override LocalisableString Description => "Less zoom...";
|
public override LocalisableString Description => "Less zoom...";
|
||||||
|
|
||||||
[SettingSource("Speed decrease", "The actual decrease to apply")]
|
[SettingSource("Speed decrease", "The actual decrease to apply")]
|
||||||
public override BindableNumber<double> SpeedChange { get; } = new BindableDouble
|
public override BindableNumber<double> SpeedChange { get; } = new BindableDouble(0.75)
|
||||||
{
|
{
|
||||||
MinValue = 0.5,
|
MinValue = 0.5,
|
||||||
MaxValue = 0.99,
|
MaxValue = 0.99,
|
||||||
Default = 0.75,
|
|
||||||
Value = 0.75,
|
|
||||||
Precision = 0.01,
|
Precision = 0.01,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -36,34 +36,20 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
private readonly BindableNumber<int> currentCombo = new BindableInt();
|
private readonly BindableNumber<int> currentCombo = new BindableInt();
|
||||||
|
|
||||||
[SettingSource("Enable metronome", "Add a metronome beat to help you keep track of the rhythm.")]
|
[SettingSource("Enable metronome", "Add a metronome beat to help you keep track of the rhythm.")]
|
||||||
public BindableBool EnableMetronome { get; } = new BindableBool
|
public BindableBool EnableMetronome { get; } = new BindableBool(true);
|
||||||
{
|
|
||||||
Default = true,
|
|
||||||
Value = true
|
|
||||||
};
|
|
||||||
|
|
||||||
[SettingSource("Final volume at combo", "The combo count at which point the track reaches its final volume.", SettingControlType = typeof(SettingsSlider<int, MuteComboSlider>))]
|
[SettingSource("Final volume at combo", "The combo count at which point the track reaches its final volume.", SettingControlType = typeof(SettingsSlider<int, MuteComboSlider>))]
|
||||||
public BindableInt MuteComboCount { get; } = new BindableInt
|
public BindableInt MuteComboCount { get; } = new BindableInt(100)
|
||||||
{
|
{
|
||||||
Default = 100,
|
|
||||||
Value = 100,
|
|
||||||
MinValue = 0,
|
MinValue = 0,
|
||||||
MaxValue = 500,
|
MaxValue = 500,
|
||||||
};
|
};
|
||||||
|
|
||||||
[SettingSource("Start muted", "Increase volume as combo builds.")]
|
[SettingSource("Start muted", "Increase volume as combo builds.")]
|
||||||
public BindableBool InverseMuting { get; } = new BindableBool
|
public BindableBool InverseMuting { get; } = new BindableBool();
|
||||||
{
|
|
||||||
Default = false,
|
|
||||||
Value = false
|
|
||||||
};
|
|
||||||
|
|
||||||
[SettingSource("Mute hit sounds", "Hit sounds are also muted alongside the track.")]
|
[SettingSource("Mute hit sounds", "Hit sounds are also muted alongside the track.")]
|
||||||
public BindableBool AffectsHitSounds { get; } = new BindableBool
|
public BindableBool AffectsHitSounds { get; } = new BindableBool(true);
|
||||||
{
|
|
||||||
Default = true,
|
|
||||||
Value = true
|
|
||||||
};
|
|
||||||
|
|
||||||
protected ModMuted()
|
protected ModMuted()
|
||||||
{
|
{
|
||||||
|
@ -6,7 +6,9 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Overlays.Settings;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
@ -34,6 +36,11 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
|
|
||||||
protected float ComboBasedAlpha;
|
protected float ComboBasedAlpha;
|
||||||
|
|
||||||
|
[SettingSource(
|
||||||
|
"Hidden at combo",
|
||||||
|
"The combo count at which the cursor becomes completely hidden",
|
||||||
|
SettingControlType = typeof(SettingsSlider<int, HiddenComboSlider>)
|
||||||
|
)]
|
||||||
public abstract BindableInt HiddenComboCount { get; }
|
public abstract BindableInt HiddenComboCount { get; }
|
||||||
|
|
||||||
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
|
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
|
||||||
|
@ -18,10 +18,6 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
public override double ScoreMultiplier => 1;
|
public override double ScoreMultiplier => 1;
|
||||||
|
|
||||||
[SettingSource("Seed", "Use a custom seed instead of a random one", SettingControlType = typeof(SettingsNumberBox))]
|
[SettingSource("Seed", "Use a custom seed instead of a random one", SettingControlType = typeof(SettingsNumberBox))]
|
||||||
public Bindable<int?> Seed { get; } = new Bindable<int?>
|
public Bindable<int?> Seed { get; } = new Bindable<int?>();
|
||||||
{
|
|
||||||
Default = null,
|
|
||||||
Value = null
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,10 +39,8 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
private double finalRateTime;
|
private double finalRateTime;
|
||||||
private double beginRampTime;
|
private double beginRampTime;
|
||||||
|
|
||||||
public BindableNumber<double> SpeedChange { get; } = new BindableDouble
|
public BindableNumber<double> SpeedChange { get; } = new BindableDouble(1)
|
||||||
{
|
{
|
||||||
Default = 1,
|
|
||||||
Value = 1,
|
|
||||||
Precision = 0.01,
|
Precision = 0.01,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ using System.Linq;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Configuration;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
{
|
{
|
||||||
@ -17,32 +16,21 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
public override LocalisableString Description => "Sloooow doooown...";
|
public override LocalisableString Description => "Sloooow doooown...";
|
||||||
public override IconUsage? Icon => FontAwesome.Solid.ChevronCircleDown;
|
public override IconUsage? Icon => FontAwesome.Solid.ChevronCircleDown;
|
||||||
|
|
||||||
[SettingSource("Initial rate", "The starting speed of the track")]
|
public override BindableNumber<double> InitialRate { get; } = new BindableDouble(1)
|
||||||
public override BindableNumber<double> InitialRate { get; } = new BindableDouble
|
|
||||||
{
|
{
|
||||||
MinValue = 0.51,
|
MinValue = 0.51,
|
||||||
MaxValue = 2,
|
MaxValue = 2,
|
||||||
Default = 1,
|
|
||||||
Value = 1,
|
|
||||||
Precision = 0.01,
|
Precision = 0.01,
|
||||||
};
|
};
|
||||||
|
|
||||||
[SettingSource("Final rate", "The speed increase to ramp towards")]
|
public override BindableNumber<double> FinalRate { get; } = new BindableDouble(0.75)
|
||||||
public override BindableNumber<double> FinalRate { get; } = new BindableDouble
|
|
||||||
{
|
{
|
||||||
MinValue = 0.5,
|
MinValue = 0.5,
|
||||||
MaxValue = 1.99,
|
MaxValue = 1.99,
|
||||||
Default = 0.75,
|
|
||||||
Value = 0.75,
|
|
||||||
Precision = 0.01,
|
Precision = 0.01,
|
||||||
};
|
};
|
||||||
|
|
||||||
[SettingSource("Adjust pitch", "Should pitch be adjusted with speed")]
|
public override BindableBool AdjustPitch { get; } = new BindableBool(true);
|
||||||
public override BindableBool AdjustPitch { get; } = new BindableBool
|
|
||||||
{
|
|
||||||
Default = true,
|
|
||||||
Value = true
|
|
||||||
};
|
|
||||||
|
|
||||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModWindUp)).ToArray();
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModWindUp)).ToArray();
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ using System.Linq;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Configuration;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
{
|
{
|
||||||
@ -17,32 +16,21 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
public override LocalisableString Description => "Can you keep up?";
|
public override LocalisableString Description => "Can you keep up?";
|
||||||
public override IconUsage? Icon => FontAwesome.Solid.ChevronCircleUp;
|
public override IconUsage? Icon => FontAwesome.Solid.ChevronCircleUp;
|
||||||
|
|
||||||
[SettingSource("Initial rate", "The starting speed of the track")]
|
public override BindableNumber<double> InitialRate { get; } = new BindableDouble(1)
|
||||||
public override BindableNumber<double> InitialRate { get; } = new BindableDouble
|
|
||||||
{
|
{
|
||||||
MinValue = 0.5,
|
MinValue = 0.5,
|
||||||
MaxValue = 1.99,
|
MaxValue = 1.99,
|
||||||
Default = 1,
|
|
||||||
Value = 1,
|
|
||||||
Precision = 0.01,
|
Precision = 0.01,
|
||||||
};
|
};
|
||||||
|
|
||||||
[SettingSource("Final rate", "The speed increase to ramp towards")]
|
public override BindableNumber<double> FinalRate { get; } = new BindableDouble(1.5)
|
||||||
public override BindableNumber<double> FinalRate { get; } = new BindableDouble
|
|
||||||
{
|
{
|
||||||
MinValue = 0.51,
|
MinValue = 0.51,
|
||||||
MaxValue = 2,
|
MaxValue = 2,
|
||||||
Default = 1.5,
|
|
||||||
Value = 1.5,
|
|
||||||
Precision = 0.01,
|
Precision = 0.01,
|
||||||
};
|
};
|
||||||
|
|
||||||
[SettingSource("Adjust pitch", "Should pitch be adjusted with speed")]
|
public override BindableBool AdjustPitch { get; } = new BindableBool(true);
|
||||||
public override BindableBool AdjustPitch { get; } = new BindableBool
|
|
||||||
{
|
|
||||||
Default = true,
|
|
||||||
Value = true
|
|
||||||
};
|
|
||||||
|
|
||||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModWindDown)).ToArray();
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModWindDown)).ToArray();
|
||||||
|
|
||||||
|
@ -651,7 +651,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This does not affect the time offset provided to invocations of <see cref="CheckForResult"/>.
|
/// This does not affect the time offset provided to invocations of <see cref="CheckForResult"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
protected virtual double MaximumJudgementOffset => HitObject.HitWindows?.WindowFor(HitResult.Miss) ?? 0;
|
public virtual double MaximumJudgementOffset => HitObject.HitWindows?.WindowFor(HitResult.Miss) ?? 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies the <see cref="Result"/> of this <see cref="DrawableHitObject"/>, notifying responders such as
|
/// Applies the <see cref="Result"/> of this <see cref="DrawableHitObject"/>, notifying responders such as
|
||||||
|
@ -60,7 +60,6 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly BindableDouble TimeRange = new BindableDouble(time_span_default)
|
protected readonly BindableDouble TimeRange = new BindableDouble(time_span_default)
|
||||||
{
|
{
|
||||||
Default = time_span_default,
|
|
||||||
MinValue = time_span_min,
|
MinValue = time_span_min,
|
||||||
MaxValue = time_span_max
|
MaxValue = time_span_max
|
||||||
};
|
};
|
||||||
|
@ -3,11 +3,12 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Framework.Layout;
|
using osu.Framework.Layout;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
@ -126,6 +127,16 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
|
|
||||||
private float scrollLength => scrollingAxis == Direction.Horizontal ? DrawWidth : DrawHeight;
|
private float scrollLength => scrollingAxis == Direction.Horizontal ? DrawWidth : DrawHeight;
|
||||||
|
|
||||||
|
public override void Add(HitObjectLifetimeEntry entry)
|
||||||
|
{
|
||||||
|
// Scroll info is not available until loaded.
|
||||||
|
// The lifetime of all entries will be updated in the first Update.
|
||||||
|
if (IsLoaded)
|
||||||
|
setComputedLifetimeStart(entry);
|
||||||
|
|
||||||
|
base.Add(entry);
|
||||||
|
}
|
||||||
|
|
||||||
protected override void AddDrawable(HitObjectLifetimeEntry entry, DrawableHitObject drawable)
|
protected override void AddDrawable(HitObjectLifetimeEntry entry, DrawableHitObject drawable)
|
||||||
{
|
{
|
||||||
base.AddDrawable(entry, drawable);
|
base.AddDrawable(entry, drawable);
|
||||||
@ -144,7 +155,6 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
|
|
||||||
private void invalidateHitObject(DrawableHitObject hitObject)
|
private void invalidateHitObject(DrawableHitObject hitObject)
|
||||||
{
|
{
|
||||||
hitObject.LifetimeStart = computeOriginAdjustedLifetimeStart(hitObject);
|
|
||||||
layoutComputed.Remove(hitObject);
|
layoutComputed.Remove(hitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,10 +166,8 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
|
|
||||||
layoutComputed.Clear();
|
layoutComputed.Clear();
|
||||||
|
|
||||||
// Reset lifetime to the conservative estimation.
|
|
||||||
// If a drawable becomes alive by this lifetime, its lifetime will be updated to a more precise lifetime in the next update.
|
|
||||||
foreach (var entry in Entries)
|
foreach (var entry in Entries)
|
||||||
entry.SetInitialLifetime();
|
setComputedLifetimeStart(entry);
|
||||||
|
|
||||||
scrollingInfo.Algorithm.Reset();
|
scrollingInfo.Algorithm.Reset();
|
||||||
|
|
||||||
@ -186,35 +194,46 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private double computeOriginAdjustedLifetimeStart(DrawableHitObject hitObject)
|
/// <summary>
|
||||||
|
/// Get a conservative maximum bounding box of a <see cref="DrawableHitObject"/> corresponding to <paramref name="entry"/>.
|
||||||
|
/// It is used to calculate when the hit object appears.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual RectangleF GetConservativeBoundingBox(HitObjectLifetimeEntry entry) => new RectangleF().Inflate(100);
|
||||||
|
|
||||||
|
private double computeDisplayStartTime(HitObjectLifetimeEntry entry)
|
||||||
{
|
{
|
||||||
// Origin position may be relative to the parent size
|
RectangleF boundingBox = GetConservativeBoundingBox(entry);
|
||||||
Debug.Assert(hitObject.Parent != null);
|
float startOffset = 0;
|
||||||
|
|
||||||
float originAdjustment = 0.0f;
|
|
||||||
|
|
||||||
// calculate the dimension of the part of the hitobject that should already be visible
|
|
||||||
// when the hitobject origin first appears inside the scrolling container
|
|
||||||
switch (direction.Value)
|
switch (direction.Value)
|
||||||
{
|
{
|
||||||
case ScrollingDirection.Up:
|
case ScrollingDirection.Right:
|
||||||
originAdjustment = hitObject.OriginPosition.Y;
|
startOffset = boundingBox.Right;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ScrollingDirection.Down:
|
case ScrollingDirection.Down:
|
||||||
originAdjustment = hitObject.DrawHeight - hitObject.OriginPosition.Y;
|
startOffset = boundingBox.Bottom;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ScrollingDirection.Left:
|
case ScrollingDirection.Left:
|
||||||
originAdjustment = hitObject.OriginPosition.X;
|
startOffset = -boundingBox.Left;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ScrollingDirection.Right:
|
case ScrollingDirection.Up:
|
||||||
originAdjustment = hitObject.DrawWidth - hitObject.OriginPosition.X;
|
startOffset = -boundingBox.Top;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return scrollingInfo.Algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, originAdjustment, timeRange.Value, scrollLength);
|
return scrollingInfo.Algorithm.GetDisplayStartTime(entry.HitObject.StartTime, startOffset, timeRange.Value, scrollLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setComputedLifetimeStart(HitObjectLifetimeEntry entry)
|
||||||
|
{
|
||||||
|
double computedStartTime = computeDisplayStartTime(entry);
|
||||||
|
|
||||||
|
// always load the hitobject before its first judgement offset
|
||||||
|
double judgementOffset = entry.HitObject.HitWindows?.WindowFor(Scoring.HitResult.Miss) ?? 0;
|
||||||
|
entry.LifetimeStart = Math.Min(entry.HitObject.StartTime - judgementOffset, computedStartTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateLayoutRecursive(DrawableHitObject hitObject)
|
private void updateLayoutRecursive(DrawableHitObject hitObject)
|
||||||
@ -232,8 +251,9 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
{
|
{
|
||||||
updateLayoutRecursive(obj);
|
updateLayoutRecursive(obj);
|
||||||
|
|
||||||
// Nested hitobjects don't need to scroll, but they do need accurate positions
|
// Nested hitobjects don't need to scroll, but they do need accurate positions and start lifetime
|
||||||
updatePosition(obj, hitObject.HitObject.StartTime);
|
updatePosition(obj, hitObject.HitObject.StartTime);
|
||||||
|
setComputedLifetimeStart(obj.Entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,8 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual Vector2 ScreenSpacePositionAtTime(double time) => HitObjectContainer.ScreenSpacePositionAtTime(time);
|
public virtual Vector2 ScreenSpacePositionAtTime(double time) => HitObjectContainer.ScreenSpacePositionAtTime(time);
|
||||||
|
|
||||||
protected sealed override HitObjectContainer CreateHitObjectContainer() => new ScrollingHitObjectContainer();
|
protected sealed override HitObjectContainer CreateHitObjectContainer() => CreateScrollingHitObjectContainer();
|
||||||
|
|
||||||
|
protected virtual ScrollingHitObjectContainer CreateScrollingHitObjectContainer() => new ScrollingHitObjectContainer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,12 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Diagnostics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Caching;
|
using osu.Framework.Caching;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Screens.Edit.Components.Timelines.Summary.Parts;
|
using osu.Game.Screens.Edit.Components.Timelines.Summary.Parts;
|
||||||
@ -34,8 +35,6 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuColour colours { get; set; }
|
private OsuColour colours { get; set; }
|
||||||
|
|
||||||
private static readonly int highest_divisor = BindableBeatDivisor.PREDEFINED_DIVISORS.Last();
|
|
||||||
|
|
||||||
public TimelineTickDisplay()
|
public TimelineTickDisplay()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
@ -80,20 +79,19 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
if (timeline != null)
|
if (timeline == null || DrawWidth <= 0) return;
|
||||||
|
|
||||||
|
(float, float) newRange = (
|
||||||
|
(ToLocalSpace(timeline.ScreenSpaceDrawQuad.TopLeft).X - PointVisualisation.MAX_WIDTH * 2) / DrawWidth * Content.RelativeChildSize.X,
|
||||||
|
(ToLocalSpace(timeline.ScreenSpaceDrawQuad.TopRight).X + PointVisualisation.MAX_WIDTH * 2) / DrawWidth * Content.RelativeChildSize.X);
|
||||||
|
|
||||||
|
if (visibleRange != newRange)
|
||||||
{
|
{
|
||||||
var newRange = (
|
visibleRange = newRange;
|
||||||
(ToLocalSpace(timeline.ScreenSpaceDrawQuad.TopLeft).X - PointVisualisation.MAX_WIDTH * 2) / DrawWidth * Content.RelativeChildSize.X,
|
|
||||||
(ToLocalSpace(timeline.ScreenSpaceDrawQuad.TopRight).X + PointVisualisation.MAX_WIDTH * 2) / DrawWidth * Content.RelativeChildSize.X);
|
|
||||||
|
|
||||||
if (visibleRange != newRange)
|
// actual regeneration only needs to occur if we've passed one of the known next min/max tick boundaries.
|
||||||
{
|
if (nextMinTick == null || nextMaxTick == null || (visibleRange.min < nextMinTick || visibleRange.max > nextMaxTick))
|
||||||
visibleRange = newRange;
|
tickCache.Invalidate();
|
||||||
|
|
||||||
// actual regeneration only needs to occur if we've passed one of the known next min/max tick boundaries.
|
|
||||||
if (nextMinTick == null || nextMaxTick == null || (visibleRange.min < nextMinTick || visibleRange.max > nextMaxTick))
|
|
||||||
tickCache.Invalidate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tickCache.IsValid)
|
if (!tickCache.IsValid)
|
||||||
@ -151,6 +149,20 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Children.Count > 512)
|
||||||
|
{
|
||||||
|
// There should always be a sanely small number of ticks rendered.
|
||||||
|
// If this assertion triggers, either the zoom logic is broken or a beatmap is
|
||||||
|
// probably doing weird things...
|
||||||
|
//
|
||||||
|
// Let's hope the latter never happens.
|
||||||
|
// If it does, we can choose to either fix it or ignore it as an outlier.
|
||||||
|
string message = $"Timeline is rendering many ticks ({Children.Count})";
|
||||||
|
|
||||||
|
Logger.Log(message);
|
||||||
|
Debug.Fail(message);
|
||||||
|
}
|
||||||
|
|
||||||
int usedDrawables = drawableIndex;
|
int usedDrawables = drawableIndex;
|
||||||
|
|
||||||
// save a few drawables beyond the currently used for edge cases.
|
// save a few drawables beyond the currently used for edge cases.
|
||||||
|
@ -56,7 +56,14 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
protected ZoomableScrollContainer()
|
protected ZoomableScrollContainer()
|
||||||
: base(Direction.Horizontal)
|
: base(Direction.Horizontal)
|
||||||
{
|
{
|
||||||
base.Content.Add(zoomedContent = new Container { RelativeSizeAxes = Axes.Y });
|
base.Content.Add(zoomedContent = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
// We must hide content until SetupZoom is called.
|
||||||
|
// If not, a child component that relies on its DrawWidth (via RelativeSizeAxes) may see a very incorrect value
|
||||||
|
// momentarily, as noticed in the TimelineTickDisplay, which would render thousands of ticks incorrectly.
|
||||||
|
Alpha = 0,
|
||||||
|
});
|
||||||
|
|
||||||
AddLayout(zoomedContentWidthCache);
|
AddLayout(zoomedContentWidthCache);
|
||||||
}
|
}
|
||||||
@ -94,6 +101,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
maxZoom = maximum;
|
maxZoom = maximum;
|
||||||
CurrentZoom = zoomTarget = initial;
|
CurrentZoom = zoomTarget = initial;
|
||||||
isZoomSetUp = true;
|
isZoomSetUp = true;
|
||||||
|
|
||||||
|
zoomedContent.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -118,9 +127,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
CurrentZoom = zoomTarget = newZoom;
|
CurrentZoom = zoomTarget = newZoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void UpdateAfterChildren()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.UpdateAfterChildren();
|
||||||
|
|
||||||
if (!zoomedContentWidthCache.IsValid)
|
if (!zoomedContentWidthCache.IsValid)
|
||||||
updateZoomedContentWidth();
|
updateZoomedContentWidth();
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
@ -16,7 +14,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components
|
|||||||
public class MatchLeaderboard : Leaderboard<MatchLeaderboardScope, APIUserScoreAggregate>
|
public class MatchLeaderboard : Leaderboard<MatchLeaderboardScope, APIUserScoreAggregate>
|
||||||
{
|
{
|
||||||
[Resolved(typeof(Room), nameof(Room.RoomID))]
|
[Resolved(typeof(Room), nameof(Room.RoomID))]
|
||||||
private Bindable<long?> roomId { get; set; }
|
private Bindable<long?> roomId { get; set; } = null!;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
@ -33,7 +31,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components
|
|||||||
|
|
||||||
protected override bool IsOnlineScope => true;
|
protected override bool IsOnlineScope => true;
|
||||||
|
|
||||||
protected override APIRequest FetchScores(CancellationToken cancellationToken)
|
protected override APIRequest? FetchScores(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (roomId.Value == null)
|
if (roomId.Value == null)
|
||||||
return null;
|
return null;
|
||||||
|
@ -54,6 +54,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
|||||||
{
|
{
|
||||||
private const float disabled_alpha = 0.2f;
|
private const float disabled_alpha = 0.2f;
|
||||||
|
|
||||||
|
public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks;
|
||||||
|
|
||||||
public Action? SettingsApplied;
|
public Action? SettingsApplied;
|
||||||
|
|
||||||
public OsuTextBox NameField = null!;
|
public OsuTextBox NameField = null!;
|
||||||
@ -424,7 +426,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
|||||||
|
|
||||||
private void hideError() => ErrorText.FadeOut(50);
|
private void hideError() => ErrorText.FadeOut(50);
|
||||||
|
|
||||||
private void onSuccess(Room room)
|
private void onSuccess(Room room) => Schedule(() =>
|
||||||
{
|
{
|
||||||
Debug.Assert(applyingSettingsOperation != null);
|
Debug.Assert(applyingSettingsOperation != null);
|
||||||
|
|
||||||
@ -432,9 +434,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
|||||||
|
|
||||||
applyingSettingsOperation.Dispose();
|
applyingSettingsOperation.Dispose();
|
||||||
applyingSettingsOperation = null;
|
applyingSettingsOperation = null;
|
||||||
}
|
});
|
||||||
|
|
||||||
private void onError(string text)
|
private void onError(string text) => Schedule(() =>
|
||||||
{
|
{
|
||||||
Debug.Assert(applyingSettingsOperation != null);
|
Debug.Assert(applyingSettingsOperation != null);
|
||||||
|
|
||||||
@ -455,7 +457,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
|||||||
|
|
||||||
applyingSettingsOperation.Dispose();
|
applyingSettingsOperation.Dispose();
|
||||||
applyingSettingsOperation = null;
|
applyingSettingsOperation = null;
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CreateOrUpdateButton : TriangleButton
|
public class CreateOrUpdateButton : TriangleButton
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Online.Multiplayer;
|
using osu.Game.Online.Multiplayer;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user