mirror of
https://github.com/ppy/osu.git
synced 2025-01-27 14:03:01 +08:00
Merge branch 'ppy:master' into editor-save-toast
This commit is contained in:
commit
ebe386c288
@ -52,7 +52,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.716.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.716.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.719.1" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.720.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. -->
|
||||||
|
@ -9,6 +9,6 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
{
|
{
|
||||||
public class CatchModDoubleTime : ModDoubleTime
|
public class CatchModDoubleTime : ModDoubleTime
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.06;
|
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
{
|
{
|
||||||
public class CatchModFlashlight : ModFlashlight<CatchHitObject>
|
public class CatchModFlashlight : ModFlashlight<CatchHitObject>
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
|
||||||
|
|
||||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||||
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
|
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
|
||||||
|
@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
{
|
{
|
||||||
public class CatchModHardRock : ModHardRock, IApplicableToBeatmapProcessor
|
public class CatchModHardRock : ModHardRock, IApplicableToBeatmapProcessor
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
|
||||||
|
|
||||||
public void ApplyToBeatmapProcessor(IBeatmapProcessor beatmapProcessor)
|
public void ApplyToBeatmapProcessor(IBeatmapProcessor beatmapProcessor)
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
public class CatchModHidden : ModHidden, IApplicableToDrawableRuleset<CatchHitObject>
|
public class CatchModHidden : ModHidden, IApplicableToDrawableRuleset<CatchHitObject>
|
||||||
{
|
{
|
||||||
public override string Description => @"Play with fading fruits.";
|
public override string Description => @"Play with fading fruits.";
|
||||||
public override double ScoreMultiplier => 1.06;
|
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1;
|
||||||
|
|
||||||
private const double fade_out_offset_multiplier = 0.6;
|
private const double fade_out_offset_multiplier = 0.6;
|
||||||
private const double fade_out_duration_multiplier = 0.44;
|
private const double fade_out_duration_multiplier = 0.44;
|
||||||
|
@ -10,6 +10,6 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
{
|
{
|
||||||
public class CatchModNightcore : ModNightcore<CatchHitObject>
|
public class CatchModNightcore : ModNightcore<CatchHitObject>
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.06;
|
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ using osu.Game.Rulesets.Objects;
|
|||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
|
||||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Screens.Edit;
|
using osu.Game.Screens.Edit;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
@ -24,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
{
|
{
|
||||||
public class SliderPlacementBlueprint : PlacementBlueprint
|
public class SliderPlacementBlueprint : PlacementBlueprint
|
||||||
{
|
{
|
||||||
public new Objects.Slider HitObject => (Objects.Slider)base.HitObject;
|
public new Slider HitObject => (Slider)base.HitObject;
|
||||||
|
|
||||||
private SliderBodyPiece bodyPiece;
|
private SliderBodyPiece bodyPiece;
|
||||||
private HitCirclePiece headCirclePiece;
|
private HitCirclePiece headCirclePiece;
|
||||||
@ -42,7 +43,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
private IDistanceSnapProvider snapProvider { get; set; }
|
private IDistanceSnapProvider snapProvider { get; set; }
|
||||||
|
|
||||||
public SliderPlacementBlueprint()
|
public SliderPlacementBlueprint()
|
||||||
: base(new Objects.Slider())
|
: base(new Slider())
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
@ -82,7 +83,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
case SliderPlacementState.Initial:
|
case SliderPlacementState.Initial:
|
||||||
BeginPlacement();
|
BeginPlacement();
|
||||||
|
|
||||||
var nearestDifficultyPoint = editorBeatmap.HitObjects.LastOrDefault(h => h.GetEndTime() < HitObject.StartTime)?.DifficultyControlPoint?.DeepClone() as DifficultyControlPoint;
|
var nearestDifficultyPoint = editorBeatmap.HitObjects
|
||||||
|
.LastOrDefault(h => h is Slider && h.GetEndTime() < HitObject.StartTime)?
|
||||||
|
.DifficultyControlPoint?.DeepClone() as DifficultyControlPoint;
|
||||||
|
|
||||||
HitObject.DifficultyControlPoint = nearestDifficultyPoint ?? new DifficultyControlPoint();
|
HitObject.DifficultyControlPoint = nearestDifficultyPoint ?? new DifficultyControlPoint();
|
||||||
HitObject.Position = ToLocalSpace(result.ScreenSpacePosition);
|
HitObject.Position = ToLocalSpace(result.ScreenSpacePosition);
|
||||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
public override IconUsage? Icon => FontAwesome.Solid.Adjust;
|
public override IconUsage? Icon => FontAwesome.Solid.Adjust;
|
||||||
public override ModType Type => ModType.DifficultyIncrease;
|
public override ModType Type => ModType.DifficultyIncrease;
|
||||||
|
|
||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
|
||||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModFlashlight) };
|
public override Type[] IncompatibleMods => new[] { typeof(OsuModFlashlight) };
|
||||||
|
|
||||||
private DrawableOsuBlinds blinds;
|
private DrawableOsuBlinds blinds;
|
||||||
|
@ -9,6 +9,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
{
|
{
|
||||||
public class OsuModDoubleTime : ModDoubleTime
|
public class OsuModDoubleTime : ModDoubleTime
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
{
|
{
|
||||||
public class OsuModFlashlight : ModFlashlight<OsuHitObject>, IApplicableToDrawableHitObject
|
public class OsuModFlashlight : ModFlashlight<OsuHitObject>, IApplicableToDrawableHitObject
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
|
||||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModBlinds)).ToArray();
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModBlinds)).ToArray();
|
||||||
|
|
||||||
private const double default_follow_delay = 120;
|
private const double default_follow_delay = 120;
|
||||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
{
|
{
|
||||||
public class OsuModHardRock : ModHardRock, IApplicableToHitObject
|
public class OsuModHardRock : ModHardRock, IApplicableToHitObject
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.06;
|
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1;
|
||||||
|
|
||||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModMirror)).ToArray();
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModMirror)).ToArray();
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
public Bindable<bool> OnlyFadeApproachCircles { get; } = new BindableBool();
|
public Bindable<bool> OnlyFadeApproachCircles { get; } = new BindableBool();
|
||||||
|
|
||||||
public override string Description => @"Play with no approach circles and fading circles/sliders.";
|
public override string Description => @"Play with no approach circles and fading circles/sliders.";
|
||||||
public override double ScoreMultiplier => 1.06;
|
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1;
|
||||||
|
|
||||||
public override Type[] IncompatibleMods => new[] { typeof(IRequiresApproachCircles), typeof(OsuModSpinIn) };
|
public override Type[] IncompatibleMods => new[] { typeof(IRequiresApproachCircles), typeof(OsuModSpinIn) };
|
||||||
|
|
||||||
|
@ -10,6 +10,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
{
|
{
|
||||||
public class OsuModNightcore : ModNightcore<OsuHitObject>
|
public class OsuModNightcore : ModNightcore<OsuHitObject>
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
// 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.Diagnostics;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
@ -32,19 +34,35 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
|
|||||||
|
|
||||||
protected override void OnTrackingChanged(ValueChangedEvent<bool> tracking)
|
protected override void OnTrackingChanged(ValueChangedEvent<bool> tracking)
|
||||||
{
|
{
|
||||||
const float scale_duration = 300f;
|
Debug.Assert(ParentObject != null);
|
||||||
const float fade_duration = 300f;
|
|
||||||
|
|
||||||
this.ScaleTo(tracking.NewValue ? DrawableSliderBall.FOLLOW_AREA : 1f, scale_duration, Easing.OutQuint)
|
const float duration = 300f;
|
||||||
.FadeTo(tracking.NewValue ? 1f : 0, fade_duration, Easing.OutQuint);
|
|
||||||
|
if (ParentObject.Judged)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (tracking.NewValue)
|
||||||
|
{
|
||||||
|
if (Precision.AlmostEquals(0, Alpha))
|
||||||
|
this.ScaleTo(1);
|
||||||
|
|
||||||
|
this.ScaleTo(DrawableSliderBall.FOLLOW_AREA, duration, Easing.OutQuint)
|
||||||
|
.FadeTo(1f, duration, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.ScaleTo(DrawableSliderBall.FOLLOW_AREA * 1.2f, duration / 2, Easing.OutQuint)
|
||||||
|
.FadeTo(0, duration / 2, Easing.OutQuint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSliderEnd()
|
protected override void OnSliderEnd()
|
||||||
{
|
{
|
||||||
const float fade_duration = 450f;
|
const float fade_duration = 300;
|
||||||
|
|
||||||
// intentionally pile on an extra FadeOut to make it happen much faster
|
// intentionally pile on an extra FadeOut to make it happen much faster
|
||||||
this.FadeOut(fade_duration / 4, Easing.Out);
|
this.ScaleTo(1, fade_duration, Easing.OutQuint);
|
||||||
|
this.FadeOut(fade_duration / 2, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Game.Rulesets.Taiko.Mods;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Tests
|
||||||
|
{
|
||||||
|
public class TestSceneTaikoPlayerLegacySkin : LegacySkinPlayerTestScene
|
||||||
|
{
|
||||||
|
protected override Ruleset CreatePlayerRuleset() => new TaikoRuleset();
|
||||||
|
|
||||||
|
protected override TestPlayer CreatePlayer(Ruleset ruleset)
|
||||||
|
{
|
||||||
|
SelectedMods.Value = new[] { new TaikoModClassic() };
|
||||||
|
return base.CreatePlayer(ruleset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,9 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
{
|
{
|
||||||
drawableTaikoRuleset = (DrawableTaikoRuleset)drawableRuleset;
|
drawableTaikoRuleset = (DrawableTaikoRuleset)drawableRuleset;
|
||||||
drawableTaikoRuleset.LockPlayfieldAspect.Value = false;
|
drawableTaikoRuleset.LockPlayfieldAspect.Value = false;
|
||||||
|
|
||||||
|
var playfield = (TaikoPlayfield)drawableRuleset.Playfield;
|
||||||
|
playfield.ClassicHitTargetPosition.Value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(Playfield playfield)
|
public void Update(Playfield playfield)
|
||||||
|
@ -9,6 +9,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
{
|
{
|
||||||
public class TaikoModDoubleTime : ModDoubleTime
|
public class TaikoModDoubleTime : ModDoubleTime
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
{
|
{
|
||||||
public class TaikoModFlashlight : ModFlashlight<TaikoHitObject>
|
public class TaikoModFlashlight : ModFlashlight<TaikoHitObject>
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
|
||||||
|
|
||||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||||
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
|
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
|
||||||
|
@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
{
|
{
|
||||||
public class TaikoModHardRock : ModHardRock
|
public class TaikoModHardRock : ModHardRock
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.06;
|
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Multiplier factor added to the scrolling speed.
|
/// Multiplier factor added to the scrolling speed.
|
||||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
public class TaikoModHidden : ModHidden, IApplicableToDrawableRuleset<TaikoHitObject>
|
public class TaikoModHidden : ModHidden, IApplicableToDrawableRuleset<TaikoHitObject>
|
||||||
{
|
{
|
||||||
public override string Description => @"Beats fade out before you hit them!";
|
public override string Description => @"Beats fade out before you hit them!";
|
||||||
public override double ScoreMultiplier => 1.06;
|
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How far away from the hit target should hitobjects start to fade out.
|
/// How far away from the hit target should hitobjects start to fade out.
|
||||||
|
@ -10,6 +10,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
{
|
{
|
||||||
public class TaikoModNightcore : ModNightcore<TaikoHitObject>
|
public class TaikoModNightcore : ModNightcore<TaikoHitObject>
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,13 +22,14 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class LegacyInputDrum : Container
|
internal class LegacyInputDrum : Container
|
||||||
{
|
{
|
||||||
|
private Container content;
|
||||||
private LegacyHalfDrum left;
|
private LegacyHalfDrum left;
|
||||||
private LegacyHalfDrum right;
|
private LegacyHalfDrum right;
|
||||||
private Container content;
|
|
||||||
|
|
||||||
public LegacyInputDrum()
|
public LegacyInputDrum()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Y;
|
||||||
|
AutoSizeAxes = Axes.X;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
|
@ -14,6 +14,7 @@ using osu.Framework.Input.Events;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osu.Game.Screens.Ranking;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -33,7 +34,8 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
{
|
{
|
||||||
sampleTriggerSource = new DrumSampleTriggerSource(hitObjectContainer);
|
sampleTriggerSource = new DrumSampleTriggerSource(hitObjectContainer);
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.X;
|
||||||
|
RelativeSizeAxes = Axes.Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -41,12 +43,32 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.InputDrum), _ => new Container
|
new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.InputDrum), _ => new DefaultInputDrum())
|
||||||
{
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
},
|
||||||
|
sampleTriggerSource
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DefaultInputDrum : AspectContainer
|
||||||
|
{
|
||||||
|
public DefaultInputDrum()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
InternalChild = new Container
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
FillMode = FillMode.Fit,
|
|
||||||
Scale = new Vector2(0.9f),
|
Scale = new Vector2(0.9f),
|
||||||
Children = new Drawable[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new TaikoHalfDrum(false)
|
new TaikoHalfDrum(false)
|
||||||
{
|
{
|
||||||
@ -71,131 +93,130 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
CentreAction = TaikoAction.RightCentre
|
CentreAction = TaikoAction.RightCentre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
|
||||||
sampleTriggerSource
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A half-drum. Contains one centre and one rim hit.
|
|
||||||
/// </summary>
|
|
||||||
private class TaikoHalfDrum : Container, IKeyBindingHandler<TaikoAction>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The key to be used for the rim of the half-drum.
|
|
||||||
/// </summary>
|
|
||||||
public TaikoAction RimAction;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The key to be used for the centre of the half-drum.
|
|
||||||
/// </summary>
|
|
||||||
public TaikoAction CentreAction;
|
|
||||||
|
|
||||||
private readonly Sprite rim;
|
|
||||||
private readonly Sprite rimHit;
|
|
||||||
private readonly Sprite centre;
|
|
||||||
private readonly Sprite centreHit;
|
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private DrumSampleTriggerSource sampleTriggerSource { get; set; }
|
|
||||||
|
|
||||||
public TaikoHalfDrum(bool flipped)
|
|
||||||
{
|
|
||||||
Masking = true;
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
rim = new Sprite
|
|
||||||
{
|
|
||||||
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.Both
|
|
||||||
},
|
|
||||||
rimHit = new Sprite
|
|
||||||
{
|
|
||||||
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Alpha = 0,
|
|
||||||
Blending = BlendingParameters.Additive,
|
|
||||||
},
|
|
||||||
centre = new Sprite
|
|
||||||
{
|
|
||||||
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Size = new Vector2(0.7f)
|
|
||||||
},
|
|
||||||
centreHit = new Sprite
|
|
||||||
{
|
|
||||||
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Size = new Vector2(0.7f),
|
|
||||||
Alpha = 0,
|
|
||||||
Blending = BlendingParameters.Additive
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
/// <summary>
|
||||||
private void load(TextureStore textures, OsuColour colours)
|
/// A half-drum. Contains one centre and one rim hit.
|
||||||
|
/// </summary>
|
||||||
|
private class TaikoHalfDrum : Container, IKeyBindingHandler<TaikoAction>
|
||||||
{
|
{
|
||||||
rim.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-outer");
|
/// <summary>
|
||||||
rimHit.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-outer-hit");
|
/// The key to be used for the rim of the half-drum.
|
||||||
centre.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-inner");
|
/// </summary>
|
||||||
centreHit.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-inner-hit");
|
public TaikoAction RimAction;
|
||||||
|
|
||||||
rimHit.Colour = colours.Blue;
|
/// <summary>
|
||||||
centreHit.Colour = colours.Pink;
|
/// The key to be used for the centre of the half-drum.
|
||||||
}
|
/// </summary>
|
||||||
|
public TaikoAction CentreAction;
|
||||||
|
|
||||||
public bool OnPressed(KeyBindingPressEvent<TaikoAction> e)
|
private readonly Sprite rim;
|
||||||
{
|
private readonly Sprite rimHit;
|
||||||
Drawable target = null;
|
private readonly Sprite centre;
|
||||||
Drawable back = null;
|
private readonly Sprite centreHit;
|
||||||
|
|
||||||
if (e.Action == CentreAction)
|
[Resolved]
|
||||||
|
private DrumSampleTriggerSource sampleTriggerSource { get; set; }
|
||||||
|
|
||||||
|
public TaikoHalfDrum(bool flipped)
|
||||||
{
|
{
|
||||||
target = centreHit;
|
Masking = true;
|
||||||
back = centre;
|
|
||||||
|
|
||||||
sampleTriggerSource.Play(HitType.Centre);
|
Children = new Drawable[]
|
||||||
}
|
{
|
||||||
else if (e.Action == RimAction)
|
rim = new Sprite
|
||||||
{
|
{
|
||||||
target = rimHit;
|
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
|
||||||
back = rim;
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
sampleTriggerSource.Play(HitType.Rim);
|
},
|
||||||
|
rimHit = new Sprite
|
||||||
|
{
|
||||||
|
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0,
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
},
|
||||||
|
centre = new Sprite
|
||||||
|
{
|
||||||
|
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Size = new Vector2(0.7f)
|
||||||
|
},
|
||||||
|
centreHit = new Sprite
|
||||||
|
{
|
||||||
|
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Size = new Vector2(0.7f),
|
||||||
|
Alpha = 0,
|
||||||
|
Blending = BlendingParameters.Additive
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target != null)
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(TextureStore textures, OsuColour colours)
|
||||||
{
|
{
|
||||||
const float scale_amount = 0.05f;
|
rim.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-outer");
|
||||||
const float alpha_amount = 0.5f;
|
rimHit.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-outer-hit");
|
||||||
|
centre.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-inner");
|
||||||
|
centreHit.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-inner-hit");
|
||||||
|
|
||||||
const float down_time = 40;
|
rimHit.Colour = colours.Blue;
|
||||||
const float up_time = 1000;
|
centreHit.Colour = colours.Pink;
|
||||||
|
|
||||||
back.ScaleTo(target.Scale.X - scale_amount, down_time, Easing.OutQuint)
|
|
||||||
.Then()
|
|
||||||
.ScaleTo(1, up_time, Easing.OutQuint);
|
|
||||||
|
|
||||||
target.Animate(
|
|
||||||
t => t.ScaleTo(target.Scale.X - scale_amount, down_time, Easing.OutQuint),
|
|
||||||
t => t.FadeTo(Math.Min(target.Alpha + alpha_amount, 1), down_time, Easing.OutQuint)
|
|
||||||
).Then(
|
|
||||||
t => t.ScaleTo(1, up_time, Easing.OutQuint),
|
|
||||||
t => t.FadeOut(up_time, Easing.OutQuint)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
public bool OnPressed(KeyBindingPressEvent<TaikoAction> e)
|
||||||
}
|
{
|
||||||
|
Drawable target = null;
|
||||||
|
Drawable back = null;
|
||||||
|
|
||||||
public void OnReleased(KeyBindingReleaseEvent<TaikoAction> e)
|
if (e.Action == CentreAction)
|
||||||
{
|
{
|
||||||
|
target = centreHit;
|
||||||
|
back = centre;
|
||||||
|
|
||||||
|
sampleTriggerSource.Play(HitType.Centre);
|
||||||
|
}
|
||||||
|
else if (e.Action == RimAction)
|
||||||
|
{
|
||||||
|
target = rimHit;
|
||||||
|
back = rim;
|
||||||
|
|
||||||
|
sampleTriggerSource.Play(HitType.Rim);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target != null)
|
||||||
|
{
|
||||||
|
const float scale_amount = 0.05f;
|
||||||
|
const float alpha_amount = 0.5f;
|
||||||
|
|
||||||
|
const float down_time = 40;
|
||||||
|
const float up_time = 1000;
|
||||||
|
|
||||||
|
back.ScaleTo(target.Scale.X - scale_amount, down_time, Easing.OutQuint)
|
||||||
|
.Then()
|
||||||
|
.ScaleTo(1, up_time, Easing.OutQuint);
|
||||||
|
|
||||||
|
target.Animate(
|
||||||
|
t => t.ScaleTo(target.Scale.X - scale_amount, down_time, Easing.OutQuint),
|
||||||
|
t => t.FadeTo(Math.Min(target.Alpha + alpha_amount, 1), down_time, Easing.OutQuint)
|
||||||
|
).Then(
|
||||||
|
t => t.ScaleTo(1, up_time, Easing.OutQuint),
|
||||||
|
t => t.FadeOut(up_time, Easing.OutQuint)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnReleased(KeyBindingReleaseEvent<TaikoAction> e)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Pooling;
|
using osu.Framework.Graphics.Pooling;
|
||||||
@ -34,6 +35,11 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public const float DEFAULT_HEIGHT = 200;
|
public const float DEFAULT_HEIGHT = 200;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the hit target should be nudged further towards the left area, matching the stable "classic" position.
|
||||||
|
/// </summary>
|
||||||
|
public Bindable<bool> ClassicHitTargetPosition = new BindableBool();
|
||||||
|
|
||||||
private Container<HitExplosion> hitExplosionContainer;
|
private Container<HitExplosion> hitExplosionContainer;
|
||||||
private Container<KiaiHitExplosion> kiaiExplosionContainer;
|
private Container<KiaiHitExplosion> kiaiExplosionContainer;
|
||||||
private JudgementContainer<DrawableTaikoJudgement> judgementContainer;
|
private JudgementContainer<DrawableTaikoJudgement> judgementContainer;
|
||||||
@ -45,8 +51,8 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
private readonly IDictionary<HitResult, HitExplosionPool> explosionPools = new Dictionary<HitResult, HitExplosionPool>();
|
private readonly IDictionary<HitResult, HitExplosionPool> explosionPools = new Dictionary<HitResult, HitExplosionPool>();
|
||||||
|
|
||||||
private ProxyContainer topLevelHitContainer;
|
private ProxyContainer topLevelHitContainer;
|
||||||
|
private InputDrum inputDrum;
|
||||||
private Container rightArea;
|
private Container rightArea;
|
||||||
private Container leftArea;
|
|
||||||
|
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// <see cref="Playfield.AddNested"/> is purposefully not called on this to prevent i.e. being able to interact
|
/// <see cref="Playfield.AddNested"/> is purposefully not called on this to prevent i.e. being able to interact
|
||||||
@ -54,14 +60,43 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
private BarLinePlayfield barLinePlayfield;
|
private BarLinePlayfield barLinePlayfield;
|
||||||
|
|
||||||
private Container hitTargetOffsetContent;
|
private Container playfieldContent;
|
||||||
|
private Container playfieldOverlay;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
|
inputDrum = new InputDrum(HitObjectContainer)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
};
|
||||||
|
|
||||||
InternalChildren = new[]
|
InternalChildren = new[]
|
||||||
{
|
{
|
||||||
new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.PlayfieldBackgroundRight), _ => new PlayfieldBackgroundRight()),
|
new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.PlayfieldBackgroundRight), _ => new PlayfieldBackgroundRight()),
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
Name = "Left overlay",
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
FillMode = FillMode.Fit,
|
||||||
|
BorderColour = colours.Gray0,
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.PlayfieldBackgroundLeft), _ => new PlayfieldBackgroundLeft()),
|
||||||
|
inputDrum.CreateProxy(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mascot = new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.Mascot), _ => Empty())
|
||||||
|
{
|
||||||
|
Origin = Anchor.BottomLeft,
|
||||||
|
Anchor = Anchor.TopLeft,
|
||||||
|
RelativePositionAxes = Axes.Y,
|
||||||
|
RelativeSizeAxes = Axes.None,
|
||||||
|
Y = 0.2f
|
||||||
|
},
|
||||||
rightArea = new Container
|
rightArea = new Container
|
||||||
{
|
{
|
||||||
Name = "Right area",
|
Name = "Right area",
|
||||||
@ -71,7 +106,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Name = "Masked elements before hit objects",
|
Name = "Elements before hit objects",
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
FillMode = FillMode.Fit,
|
FillMode = FillMode.Fit,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
@ -86,22 +121,28 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hitTargetOffsetContent = new Container
|
new Container
|
||||||
{
|
{
|
||||||
|
Name = "Masked hit objects content",
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
Child = playfieldContent = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
barLinePlayfield = new BarLinePlayfield(),
|
||||||
|
HitObjectContainer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
playfieldOverlay = new Container
|
||||||
|
{
|
||||||
|
Name = "Elements after hit objects",
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
barLinePlayfield = new BarLinePlayfield(),
|
drumRollHitContainer = new DrumRollHitContainer(),
|
||||||
new Container
|
|
||||||
{
|
|
||||||
Name = "Hit objects",
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
HitObjectContainer,
|
|
||||||
drumRollHitContainer = new DrumRollHitContainer()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
kiaiExplosionContainer = new Container<KiaiHitExplosion>
|
kiaiExplosionContainer = new Container<KiaiHitExplosion>
|
||||||
{
|
{
|
||||||
Name = "Kiai hit explosions",
|
Name = "Kiai hit explosions",
|
||||||
@ -117,36 +158,15 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
leftArea = new Container
|
|
||||||
{
|
|
||||||
Name = "Left overlay",
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
FillMode = FillMode.Fit,
|
|
||||||
BorderColour = colours.Gray0,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.PlayfieldBackgroundLeft), _ => new PlayfieldBackgroundLeft()),
|
|
||||||
new InputDrum(HitObjectContainer)
|
|
||||||
{
|
|
||||||
Anchor = Anchor.CentreLeft,
|
|
||||||
Origin = Anchor.CentreLeft,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mascot = new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.Mascot), _ => Empty())
|
|
||||||
{
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
Anchor = Anchor.TopLeft,
|
|
||||||
RelativePositionAxes = Axes.Y,
|
|
||||||
RelativeSizeAxes = Axes.None,
|
|
||||||
Y = 0.2f
|
|
||||||
},
|
|
||||||
topLevelHitContainer = new ProxyContainer
|
topLevelHitContainer = new ProxyContainer
|
||||||
{
|
{
|
||||||
Name = "Top level hit objects",
|
Name = "Top level hit objects",
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
drumRollHitContainer.CreateProxy(),
|
drumRollHitContainer.CreateProxy(),
|
||||||
|
// this is added at the end of the hierarchy to receive input before taiko objects.
|
||||||
|
// but is proxied below everything to not cover visual effects such as hit explosions.
|
||||||
|
inputDrum,
|
||||||
};
|
};
|
||||||
|
|
||||||
RegisterPool<Hit, DrawableHit>(50);
|
RegisterPool<Hit, DrawableHit>(50);
|
||||||
@ -193,8 +213,9 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
|
|
||||||
// Padding is required to be updated for elements which are based on "absolute" X sized elements.
|
// Padding is required to be updated for elements which are based on "absolute" X sized elements.
|
||||||
// This is basically allowing for correct alignment as relative pieces move around them.
|
// This is basically allowing for correct alignment as relative pieces move around them.
|
||||||
rightArea.Padding = new MarginPadding { Left = leftArea.DrawWidth };
|
rightArea.Padding = new MarginPadding { Left = inputDrum.Width };
|
||||||
hitTargetOffsetContent.Padding = new MarginPadding { Left = HitTarget.DrawWidth / 2 };
|
playfieldContent.Padding = new MarginPadding { Left = HitTarget.DrawWidth / 2 };
|
||||||
|
playfieldOverlay.Padding = new MarginPadding { Left = HitTarget.DrawWidth / 2 };
|
||||||
|
|
||||||
mascot.Scale = new Vector2(DrawHeight / DEFAULT_HEIGHT);
|
mascot.Scale = new Vector2(DrawHeight / DEFAULT_HEIGHT);
|
||||||
}
|
}
|
||||||
|
@ -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.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
@ -17,7 +15,7 @@ namespace osu.Game.Tests.Mods
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class ModDifficultyAdjustTest
|
public class ModDifficultyAdjustTest
|
||||||
{
|
{
|
||||||
private TestModDifficultyAdjust testMod;
|
private TestModDifficultyAdjust testMod = null!;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
@ -148,7 +146,7 @@ namespace osu.Game.Tests.Mods
|
|||||||
yield return new TestModDifficultyAdjust();
|
yield return new TestModDifficultyAdjust();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null)
|
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod>? mods = null)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
@ -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 NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
|
@ -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 NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
@ -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.Linq;
|
using System.Linq;
|
||||||
using Moq;
|
using Moq;
|
||||||
@ -164,19 +162,19 @@ namespace osu.Game.Tests.Mods
|
|||||||
new object[]
|
new object[]
|
||||||
{
|
{
|
||||||
new Mod[] { new OsuModHidden(), new InvalidMultiplayerMod() },
|
new Mod[] { new OsuModHidden(), new InvalidMultiplayerMod() },
|
||||||
null
|
Array.Empty<Type>()
|
||||||
},
|
},
|
||||||
// invalid free mod is valid for local.
|
// invalid free mod is valid for local.
|
||||||
new object[]
|
new object[]
|
||||||
{
|
{
|
||||||
new Mod[] { new OsuModHidden(), new InvalidMultiplayerFreeMod() },
|
new Mod[] { new OsuModHidden(), new InvalidMultiplayerFreeMod() },
|
||||||
null
|
Array.Empty<Type>()
|
||||||
},
|
},
|
||||||
// valid pair.
|
// valid pair.
|
||||||
new object[]
|
new object[]
|
||||||
{
|
{
|
||||||
new Mod[] { new OsuModHidden(), new OsuModHardRock() },
|
new Mod[] { new OsuModHidden(), new OsuModHardRock() },
|
||||||
null
|
Array.Empty<Type>()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -216,13 +214,13 @@ namespace osu.Game.Tests.Mods
|
|||||||
new object[]
|
new object[]
|
||||||
{
|
{
|
||||||
new Mod[] { new OsuModHidden(), new InvalidMultiplayerFreeMod() },
|
new Mod[] { new OsuModHidden(), new InvalidMultiplayerFreeMod() },
|
||||||
null
|
Array.Empty<Type>()
|
||||||
},
|
},
|
||||||
// valid pair.
|
// valid pair.
|
||||||
new object[]
|
new object[]
|
||||||
{
|
{
|
||||||
new Mod[] { new OsuModHidden(), new OsuModHardRock() },
|
new Mod[] { new OsuModHidden(), new OsuModHardRock() },
|
||||||
null
|
Array.Empty<Type>()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -256,19 +254,19 @@ namespace osu.Game.Tests.Mods
|
|||||||
new object[]
|
new object[]
|
||||||
{
|
{
|
||||||
new Mod[] { new OsuModHidden(), new OsuModApproachDifferent() },
|
new Mod[] { new OsuModHidden(), new OsuModApproachDifferent() },
|
||||||
null,
|
Array.Empty<Type>(),
|
||||||
},
|
},
|
||||||
// incompatible pair with derived class is valid for free mods.
|
// incompatible pair with derived class is valid for free mods.
|
||||||
new object[]
|
new object[]
|
||||||
{
|
{
|
||||||
new Mod[] { new OsuModDeflate(), new OsuModSpinIn() },
|
new Mod[] { new OsuModDeflate(), new OsuModSpinIn() },
|
||||||
null,
|
Array.Empty<Type>(),
|
||||||
},
|
},
|
||||||
// valid pair.
|
// valid pair.
|
||||||
new object[]
|
new object[]
|
||||||
{
|
{
|
||||||
new Mod[] { new OsuModHidden(), new OsuModHardRock() },
|
new Mod[] { new OsuModHidden(), new OsuModHardRock() },
|
||||||
null
|
Array.Empty<Type>()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -277,12 +275,12 @@ namespace osu.Game.Tests.Mods
|
|||||||
{
|
{
|
||||||
bool isValid = ModUtils.CheckValidForGameplay(inputMods, out var invalid);
|
bool isValid = ModUtils.CheckValidForGameplay(inputMods, out var invalid);
|
||||||
|
|
||||||
Assert.That(isValid, Is.EqualTo(expectedInvalid == null));
|
Assert.That(isValid, Is.EqualTo(expectedInvalid.Length == 0));
|
||||||
|
|
||||||
if (isValid)
|
if (isValid)
|
||||||
Assert.IsNull(invalid);
|
Assert.IsNull(invalid);
|
||||||
else
|
else
|
||||||
Assert.That(invalid.Select(t => t.GetType()), Is.EquivalentTo(expectedInvalid));
|
Assert.That(invalid?.Select(t => t.GetType()), Is.EquivalentTo(expectedInvalid));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCaseSource(nameof(invalid_multiplayer_mod_test_scenarios))]
|
[TestCaseSource(nameof(invalid_multiplayer_mod_test_scenarios))]
|
||||||
@ -290,12 +288,12 @@ namespace osu.Game.Tests.Mods
|
|||||||
{
|
{
|
||||||
bool isValid = ModUtils.CheckValidRequiredModsForMultiplayer(inputMods, out var invalid);
|
bool isValid = ModUtils.CheckValidRequiredModsForMultiplayer(inputMods, out var invalid);
|
||||||
|
|
||||||
Assert.That(isValid, Is.EqualTo(expectedInvalid == null));
|
Assert.That(isValid, Is.EqualTo(expectedInvalid.Length == 0));
|
||||||
|
|
||||||
if (isValid)
|
if (isValid)
|
||||||
Assert.IsNull(invalid);
|
Assert.IsNull(invalid);
|
||||||
else
|
else
|
||||||
Assert.That(invalid.Select(t => t.GetType()), Is.EquivalentTo(expectedInvalid));
|
Assert.That(invalid?.Select(t => t.GetType()), Is.EquivalentTo(expectedInvalid));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCaseSource(nameof(invalid_free_mod_test_scenarios))]
|
[TestCaseSource(nameof(invalid_free_mod_test_scenarios))]
|
||||||
@ -303,12 +301,12 @@ namespace osu.Game.Tests.Mods
|
|||||||
{
|
{
|
||||||
bool isValid = ModUtils.CheckValidFreeModsForMultiplayer(inputMods, out var invalid);
|
bool isValid = ModUtils.CheckValidFreeModsForMultiplayer(inputMods, out var invalid);
|
||||||
|
|
||||||
Assert.That(isValid, Is.EqualTo(expectedInvalid == null));
|
Assert.That(isValid, Is.EqualTo(expectedInvalid.Length == 0));
|
||||||
|
|
||||||
if (isValid)
|
if (isValid)
|
||||||
Assert.IsNull(invalid);
|
Assert.IsNull(invalid);
|
||||||
else
|
else
|
||||||
Assert.That(invalid.Select(t => t.GetType()), Is.EquivalentTo(expectedInvalid));
|
Assert.That(invalid?.Select(t => t.GetType()), Is.EquivalentTo(expectedInvalid));
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class CustomMod1 : Mod, IModCompatibilitySpecification
|
public abstract class CustomMod1 : Mod, IModCompatibilitySpecification
|
||||||
|
@ -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;
|
||||||
@ -29,10 +27,10 @@ namespace osu.Game.Tests.Mods
|
|||||||
[TestCase(typeof(ManiaRuleset))]
|
[TestCase(typeof(ManiaRuleset))]
|
||||||
public void TestAllMultiModsFromRulesetAreIncompatible(Type rulesetType)
|
public void TestAllMultiModsFromRulesetAreIncompatible(Type rulesetType)
|
||||||
{
|
{
|
||||||
var ruleset = (Ruleset)Activator.CreateInstance(rulesetType);
|
var ruleset = Activator.CreateInstance(rulesetType) as Ruleset;
|
||||||
Assert.That(ruleset, Is.Not.Null);
|
Assert.That(ruleset, Is.Not.Null);
|
||||||
|
|
||||||
var allMultiMods = getMultiMods(ruleset);
|
var allMultiMods = getMultiMods(ruleset!);
|
||||||
|
|
||||||
Assert.Multiple(() =>
|
Assert.Multiple(() =>
|
||||||
{
|
{
|
||||||
|
@ -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.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
@ -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 osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
@ -33,7 +31,7 @@ namespace osu.Game.Tests.Mods
|
|||||||
return Array.Empty<Mod>();
|
return Array.Empty<Mod>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => throw new NotImplementedException();
|
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod>? mods = null) => throw new NotImplementedException();
|
||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new NotImplementedException();
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ namespace osu.Game.Tests.Online
|
|||||||
{
|
{
|
||||||
AddStep("download beatmap", () => beatmaps.Download(test_db_model));
|
AddStep("download beatmap", () => beatmaps.Download(test_db_model));
|
||||||
|
|
||||||
AddStep("cancel download from request", () => beatmaps.GetExistingDownload(test_db_model).Cancel());
|
AddStep("cancel download from request", () => beatmaps.GetExistingDownload(test_db_model)!.Cancel());
|
||||||
|
|
||||||
AddUntilStep("is removed from download list", () => beatmaps.GetExistingDownload(test_db_model) == null);
|
AddUntilStep("is removed from download list", () => beatmaps.GetExistingDownload(test_db_model) == null);
|
||||||
AddAssert("is notification cancelled", () => recentNotification.State == ProgressNotificationState.Cancelled);
|
AddAssert("is notification cancelled", () => recentNotification.State == ProgressNotificationState.Cancelled);
|
||||||
|
@ -126,10 +126,10 @@ namespace osu.Game.Tests.Online
|
|||||||
AddStep("start downloading", () => beatmapDownloader.Download(testBeatmapSet));
|
AddStep("start downloading", () => beatmapDownloader.Download(testBeatmapSet));
|
||||||
addAvailabilityCheckStep("state downloading 0%", () => BeatmapAvailability.Downloading(0.0f));
|
addAvailabilityCheckStep("state downloading 0%", () => BeatmapAvailability.Downloading(0.0f));
|
||||||
|
|
||||||
AddStep("set progress 40%", () => ((TestDownloadRequest)beatmapDownloader.GetExistingDownload(testBeatmapSet)).SetProgress(0.4f));
|
AddStep("set progress 40%", () => ((TestDownloadRequest)beatmapDownloader.GetExistingDownload(testBeatmapSet))!.SetProgress(0.4f));
|
||||||
addAvailabilityCheckStep("state downloading 40%", () => BeatmapAvailability.Downloading(0.4f));
|
addAvailabilityCheckStep("state downloading 40%", () => BeatmapAvailability.Downloading(0.4f));
|
||||||
|
|
||||||
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.SetResult(true));
|
||||||
@ -246,7 +246,7 @@ namespace osu.Game.Tests.Online
|
|||||||
=> new TestDownloadRequest(set);
|
=> new TestDownloadRequest(set);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestDownloadRequest : ArchiveDownloadRequest<IBeatmapSetInfo>
|
internal class TestDownloadRequest : ArchiveDownloadRequest<IBeatmapSetInfo>
|
||||||
{
|
{
|
||||||
public new void SetProgress(float progress) => base.SetProgress(progress);
|
public new void SetProgress(float progress) => base.SetProgress(progress);
|
||||||
public new void TriggerSuccess(string filename) => base.TriggerSuccess(filename);
|
public new void TriggerSuccess(string filename) => base.TriggerSuccess(filename);
|
||||||
|
@ -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 NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
@ -19,8 +17,8 @@ namespace osu.Game.Tests.Rulesets.Mods
|
|||||||
private const double start_time = 1000;
|
private const double start_time = 1000;
|
||||||
private const double duration = 9000;
|
private const double duration = 9000;
|
||||||
|
|
||||||
private TrackVirtual track;
|
private TrackVirtual track = null!;
|
||||||
private OsuPlayfield playfield;
|
private OsuPlayfield playfield = null!;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp()
|
public void SetUp()
|
||||||
|
@ -402,16 +402,18 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestPlayStartsWithCorrectBeatmapWhileAtSongSelect()
|
public void TestPlayStartsWithCorrectBeatmapWhileAtSongSelect()
|
||||||
{
|
{
|
||||||
createRoom(() => new Room
|
PlaylistItem? item = null;
|
||||||
|
createRoom(() =>
|
||||||
{
|
{
|
||||||
Name = { Value = "Test Room" },
|
item = new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||||
Playlist =
|
|
||||||
{
|
{
|
||||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||||
{
|
};
|
||||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
return new Room
|
||||||
}
|
{
|
||||||
}
|
Name = { Value = "Test Room" },
|
||||||
|
Playlist = { item }
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
pressReadyButton();
|
pressReadyButton();
|
||||||
@ -419,7 +421,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddStep("Enter song select", () =>
|
AddStep("Enter song select", () =>
|
||||||
{
|
{
|
||||||
var currentSubScreen = ((Screens.OnlinePlay.Multiplayer.Multiplayer)multiplayerComponents.CurrentScreen).CurrentSubScreen;
|
var currentSubScreen = ((Screens.OnlinePlay.Multiplayer.Multiplayer)multiplayerComponents.CurrentScreen).CurrentSubScreen;
|
||||||
((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(multiplayerClient.ClientRoom?.Settings.PlaylistItemId);
|
((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(item);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for song select", () => this.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
|
AddUntilStep("wait for song select", () => this.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
|
||||||
@ -440,16 +442,18 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestPlayStartsWithCorrectRulesetWhileAtSongSelect()
|
public void TestPlayStartsWithCorrectRulesetWhileAtSongSelect()
|
||||||
{
|
{
|
||||||
createRoom(() => new Room
|
PlaylistItem? item = null;
|
||||||
|
createRoom(() =>
|
||||||
{
|
{
|
||||||
Name = { Value = "Test Room" },
|
item = new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||||
Playlist =
|
|
||||||
{
|
{
|
||||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||||
{
|
};
|
||||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
return new Room
|
||||||
}
|
{
|
||||||
}
|
Name = { Value = "Test Room" },
|
||||||
|
Playlist = { item }
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
pressReadyButton();
|
pressReadyButton();
|
||||||
@ -457,7 +461,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddStep("Enter song select", () =>
|
AddStep("Enter song select", () =>
|
||||||
{
|
{
|
||||||
var currentSubScreen = ((Screens.OnlinePlay.Multiplayer.Multiplayer)multiplayerComponents.CurrentScreen).CurrentSubScreen;
|
var currentSubScreen = ((Screens.OnlinePlay.Multiplayer.Multiplayer)multiplayerComponents.CurrentScreen).CurrentSubScreen;
|
||||||
((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(multiplayerClient.ClientRoom?.Settings.PlaylistItemId);
|
((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(item);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for song select", () => this.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
|
AddUntilStep("wait for song select", () => this.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
|
||||||
@ -478,16 +482,18 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestPlayStartsWithCorrectModsWhileAtSongSelect()
|
public void TestPlayStartsWithCorrectModsWhileAtSongSelect()
|
||||||
{
|
{
|
||||||
createRoom(() => new Room
|
PlaylistItem? item = null;
|
||||||
|
createRoom(() =>
|
||||||
{
|
{
|
||||||
Name = { Value = "Test Room" },
|
item = new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||||
Playlist =
|
|
||||||
{
|
{
|
||||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||||
{
|
};
|
||||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
return new Room
|
||||||
}
|
{
|
||||||
}
|
Name = { Value = "Test Room" },
|
||||||
|
Playlist = { item }
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
pressReadyButton();
|
pressReadyButton();
|
||||||
@ -495,7 +501,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddStep("Enter song select", () =>
|
AddStep("Enter song select", () =>
|
||||||
{
|
{
|
||||||
var currentSubScreen = ((Screens.OnlinePlay.Multiplayer.Multiplayer)multiplayerComponents.CurrentScreen).CurrentSubScreen;
|
var currentSubScreen = ((Screens.OnlinePlay.Multiplayer.Multiplayer)multiplayerComponents.CurrentScreen).CurrentSubScreen;
|
||||||
((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(multiplayerClient.ClientRoom?.Settings.PlaylistItemId);
|
((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(item);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for song select", () => this.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
|
AddUntilStep("wait for song select", () => this.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
|
||||||
|
@ -108,6 +108,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
Version = "2018.712.0",
|
Version = "2018.712.0",
|
||||||
DisplayVersion = "2018.712.0",
|
DisplayVersion = "2018.712.0",
|
||||||
UpdateStream = streams[OsuGameBase.CLIENT_STREAM_NAME],
|
UpdateStream = streams[OsuGameBase.CLIENT_STREAM_NAME],
|
||||||
|
CreatedAt = new DateTime(2018, 7, 12),
|
||||||
ChangelogEntries = new List<APIChangelogEntry>
|
ChangelogEntries = new List<APIChangelogEntry>
|
||||||
{
|
{
|
||||||
new APIChangelogEntry
|
new APIChangelogEntry
|
||||||
@ -171,6 +172,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
{
|
{
|
||||||
Version = "2019.920.0",
|
Version = "2019.920.0",
|
||||||
DisplayVersion = "2019.920.0",
|
DisplayVersion = "2019.920.0",
|
||||||
|
CreatedAt = new DateTime(2019, 9, 20),
|
||||||
UpdateStream = new APIUpdateStream
|
UpdateStream = new APIUpdateStream
|
||||||
{
|
{
|
||||||
Name = "Test",
|
Name = "Test",
|
||||||
|
@ -255,18 +255,25 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
};
|
};
|
||||||
|
|
||||||
const int initial_great_count = 2000;
|
const int initial_great_count = 2000;
|
||||||
|
const int initial_tick_count = 100;
|
||||||
|
|
||||||
int greatCount = initial_great_count;
|
int greatCount = initial_great_count;
|
||||||
|
int tickCount = initial_tick_count;
|
||||||
|
|
||||||
foreach (var s in scores.Scores)
|
foreach (var s in scores.Scores)
|
||||||
{
|
{
|
||||||
s.Statistics = new Dictionary<HitResult, int>
|
s.Statistics = new Dictionary<HitResult, int>
|
||||||
{
|
{
|
||||||
{ HitResult.Great, greatCount -= 100 },
|
{ HitResult.Great, greatCount },
|
||||||
|
{ HitResult.LargeTickHit, tickCount },
|
||||||
{ HitResult.Ok, RNG.Next(100) },
|
{ HitResult.Ok, RNG.Next(100) },
|
||||||
{ HitResult.Meh, RNG.Next(100) },
|
{ HitResult.Meh, RNG.Next(100) },
|
||||||
{ HitResult.Miss, initial_great_count - greatCount }
|
{ HitResult.Miss, initial_great_count - greatCount },
|
||||||
|
{ HitResult.LargeTickMiss, initial_tick_count - tickCount },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
greatCount -= 100;
|
||||||
|
tickCount -= RNG.Next(1, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
return scores;
|
return scores;
|
||||||
|
File diff suppressed because one or more lines are too long
@ -825,7 +825,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
checkVisibleItemCount(true, 15);
|
checkVisibleItemCount(true, 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadBeatmaps(List<BeatmapSetInfo> beatmapSets = null, Func<FilterCriteria> initialCriteria = null, Action<BeatmapCarousel> carouselAdjust = null, int? count = null, bool randomDifficulties = false)
|
private void loadBeatmaps(List<BeatmapSetInfo> beatmapSets = null, Func<FilterCriteria> initialCriteria = null, Action<BeatmapCarousel> carouselAdjust = null, int? count = null,
|
||||||
|
bool randomDifficulties = false)
|
||||||
{
|
{
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
|
@ -0,0 +1,156 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Screens.Select;
|
||||||
|
using osu.Game.Screens.Select.Carousel;
|
||||||
|
using osu.Game.Tests.Online;
|
||||||
|
using osu.Game.Tests.Resources;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.SongSelect
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TestSceneUpdateBeatmapSetButton : OsuManualInputManagerTestScene
|
||||||
|
{
|
||||||
|
private BeatmapCarousel carousel = null!;
|
||||||
|
|
||||||
|
private TestSceneOnlinePlayBeatmapAvailabilityTracker.TestBeatmapModelDownloader beatmapDownloader = null!;
|
||||||
|
|
||||||
|
private BeatmapSetInfo testBeatmapSetInfo = null!;
|
||||||
|
|
||||||
|
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||||
|
{
|
||||||
|
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||||
|
|
||||||
|
var importer = parent.Get<BeatmapManager>();
|
||||||
|
|
||||||
|
dependencies.CacheAs<BeatmapModelDownloader>(beatmapDownloader = new TestSceneOnlinePlayBeatmapAvailabilityTracker.TestBeatmapModelDownloader(importer, API));
|
||||||
|
return dependencies;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UpdateBeatmapSetButton? getUpdateButton() => carousel.ChildrenOfType<UpdateBeatmapSetButton>().SingleOrDefault();
|
||||||
|
|
||||||
|
[SetUpSteps]
|
||||||
|
public void SetUpSteps()
|
||||||
|
{
|
||||||
|
AddStep("create carousel", () =>
|
||||||
|
{
|
||||||
|
Child = carousel = new BeatmapCarousel
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
BeatmapSets = new List<BeatmapSetInfo>
|
||||||
|
{
|
||||||
|
(testBeatmapSetInfo = TestResources.CreateTestBeatmapSetInfo()),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("wait for load", () => carousel.BeatmapSetsLoaded);
|
||||||
|
|
||||||
|
AddAssert("update button not visible", () => getUpdateButton() == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestDownloadToCompletion()
|
||||||
|
{
|
||||||
|
ArchiveDownloadRequest<IBeatmapSetInfo>? downloadRequest = null;
|
||||||
|
|
||||||
|
AddStep("update online hash", () =>
|
||||||
|
{
|
||||||
|
testBeatmapSetInfo.Beatmaps.First().OnlineMD5Hash = "different hash";
|
||||||
|
testBeatmapSetInfo.Beatmaps.First().LastOnlineUpdate = DateTimeOffset.Now;
|
||||||
|
|
||||||
|
carousel.UpdateBeatmapSet(testBeatmapSetInfo);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("only one set visible", () => carousel.ChildrenOfType<DrawableCarouselBeatmapSet>().Count() == 1);
|
||||||
|
AddUntilStep("update button visible", () => getUpdateButton() != null);
|
||||||
|
|
||||||
|
AddStep("click button", () => getUpdateButton()?.TriggerClick());
|
||||||
|
|
||||||
|
AddUntilStep("wait for download started", () =>
|
||||||
|
{
|
||||||
|
downloadRequest = beatmapDownloader.GetExistingDownload(testBeatmapSetInfo);
|
||||||
|
return downloadRequest != null;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("wait for button disabled", () => getUpdateButton()?.Enabled.Value == false);
|
||||||
|
|
||||||
|
AddUntilStep("progress download to completion", () =>
|
||||||
|
{
|
||||||
|
if (downloadRequest is TestSceneOnlinePlayBeatmapAvailabilityTracker.TestDownloadRequest testRequest)
|
||||||
|
{
|
||||||
|
testRequest.SetProgress(testRequest.Progress + 0.1f);
|
||||||
|
|
||||||
|
if (testRequest.Progress >= 1)
|
||||||
|
{
|
||||||
|
testRequest.TriggerSuccess();
|
||||||
|
|
||||||
|
// usually this would be done by the import process.
|
||||||
|
testBeatmapSetInfo.Beatmaps.First().MD5Hash = "different hash";
|
||||||
|
testBeatmapSetInfo.Beatmaps.First().LastOnlineUpdate = DateTimeOffset.Now;
|
||||||
|
|
||||||
|
// usually this would be done by a realm subscription.
|
||||||
|
carousel.UpdateBeatmapSet(testBeatmapSetInfo);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestDownloadFailed()
|
||||||
|
{
|
||||||
|
ArchiveDownloadRequest<IBeatmapSetInfo>? downloadRequest = null;
|
||||||
|
|
||||||
|
AddStep("update online hash", () =>
|
||||||
|
{
|
||||||
|
testBeatmapSetInfo.Beatmaps.First().OnlineMD5Hash = "different hash";
|
||||||
|
testBeatmapSetInfo.Beatmaps.First().LastOnlineUpdate = DateTimeOffset.Now;
|
||||||
|
|
||||||
|
carousel.UpdateBeatmapSet(testBeatmapSetInfo);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("only one set visible", () => carousel.ChildrenOfType<DrawableCarouselBeatmapSet>().Count() == 1);
|
||||||
|
AddUntilStep("update button visible", () => getUpdateButton() != null);
|
||||||
|
|
||||||
|
AddStep("click button", () => getUpdateButton()?.TriggerClick());
|
||||||
|
|
||||||
|
AddUntilStep("wait for download started", () =>
|
||||||
|
{
|
||||||
|
downloadRequest = beatmapDownloader.GetExistingDownload(testBeatmapSetInfo);
|
||||||
|
return downloadRequest != null;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("wait for button disabled", () => getUpdateButton()?.Enabled.Value == false);
|
||||||
|
|
||||||
|
AddUntilStep("progress download to failure", () =>
|
||||||
|
{
|
||||||
|
if (downloadRequest is TestSceneOnlinePlayBeatmapAvailabilityTracker.TestDownloadRequest testRequest)
|
||||||
|
{
|
||||||
|
testRequest.SetProgress(testRequest.Progress + 0.1f);
|
||||||
|
|
||||||
|
if (testRequest.Progress >= 0.5f)
|
||||||
|
{
|
||||||
|
testRequest.TriggerFailure(new Exception());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("wait for button enabled", () => getUpdateButton()?.Enabled.Value == true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
51
osu.Game.Tests/Visual/UserInterface/TestSceneFPSCounter.cs
Normal file
51
osu.Game.Tests/Visual/UserInterface/TestSceneFPSCounter.cs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.UserInterface
|
||||||
|
{
|
||||||
|
public class TestSceneFPSCounter : OsuTestScene
|
||||||
|
{
|
||||||
|
[SetUpSteps]
|
||||||
|
public void SetUpSteps()
|
||||||
|
{
|
||||||
|
AddStep("create display", () =>
|
||||||
|
{
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
Colour = Color4.White,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new FPSCounter(),
|
||||||
|
new FPSCounter { Scale = new Vector2(2) },
|
||||||
|
new FPSCounter { Scale = new Vector2(4) },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBasic()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,15 +14,15 @@ namespace osu.Game.Audio
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class HitSampleInfo : ISampleInfo, IEquatable<HitSampleInfo>
|
public class HitSampleInfo : ISampleInfo, IEquatable<HitSampleInfo>
|
||||||
{
|
{
|
||||||
|
public const string HIT_NORMAL = @"hitnormal";
|
||||||
public const string HIT_WHISTLE = @"hitwhistle";
|
public const string HIT_WHISTLE = @"hitwhistle";
|
||||||
public const string HIT_FINISH = @"hitfinish";
|
public const string HIT_FINISH = @"hitfinish";
|
||||||
public const string HIT_NORMAL = @"hitnormal";
|
|
||||||
public const string HIT_CLAP = @"hitclap";
|
public const string HIT_CLAP = @"hitclap";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All valid sample addition constants.
|
/// All valid sample addition constants.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IEnumerable<string> AllAdditions => new[] { HIT_WHISTLE, HIT_CLAP, HIT_FINISH };
|
public static IEnumerable<string> AllAdditions => new[] { HIT_WHISTLE, HIT_FINISH, HIT_CLAP };
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The name of the sample to load.
|
/// The name of the sample to load.
|
||||||
|
@ -92,6 +92,16 @@ namespace osu.Game.Beatmaps
|
|||||||
[Indexed]
|
[Indexed]
|
||||||
public string MD5Hash { get; set; } = string.Empty;
|
public string MD5Hash { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string OnlineMD5Hash { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public DateTimeOffset? LastOnlineUpdate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this beatmap matches the online version, based on fetched online metadata.
|
||||||
|
/// Will return <c>true</c> if no online metadata is available.
|
||||||
|
/// </summary>
|
||||||
|
public bool MatchesOnlineVersion => LastOnlineUpdate == null || MD5Hash == OnlineMD5Hash;
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public bool Hidden { get; set; }
|
public bool Hidden { get; set; }
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
@ -14,7 +12,7 @@ namespace osu.Game.Beatmaps
|
|||||||
protected override ArchiveDownloadRequest<IBeatmapSetInfo> CreateDownloadRequest(IBeatmapSetInfo set, bool minimiseDownloadSize) =>
|
protected override ArchiveDownloadRequest<IBeatmapSetInfo> CreateDownloadRequest(IBeatmapSetInfo set, bool minimiseDownloadSize) =>
|
||||||
new DownloadBeatmapSetRequest(set, minimiseDownloadSize);
|
new DownloadBeatmapSetRequest(set, minimiseDownloadSize);
|
||||||
|
|
||||||
public override ArchiveDownloadRequest<IBeatmapSetInfo> GetExistingDownload(IBeatmapSetInfo model)
|
public override ArchiveDownloadRequest<IBeatmapSetInfo>? GetExistingDownload(IBeatmapSetInfo model)
|
||||||
=> CurrentDownloads.Find(r => r.Model.OnlineID == model.OnlineID);
|
=> CurrentDownloads.Find(r => r.Model.OnlineID == model.OnlineID);
|
||||||
|
|
||||||
public BeatmapModelDownloader(IModelImporter<BeatmapSetInfo> beatmapImporter, IAPIProvider api)
|
public BeatmapModelDownloader(IModelImporter<BeatmapSetInfo> beatmapImporter, IAPIProvider api)
|
||||||
|
50
osu.Game/Beatmaps/BeatmapOnlineChangeIngest.cs
Normal file
50
osu.Game/Beatmaps/BeatmapOnlineChangeIngest.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Database;
|
||||||
|
using osu.Game.Online.Metadata;
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Ingests any changes that happen externally to the client, reprocessing as required.
|
||||||
|
/// </summary>
|
||||||
|
public class BeatmapOnlineChangeIngest : Component
|
||||||
|
{
|
||||||
|
private readonly BeatmapUpdater beatmapUpdater;
|
||||||
|
private readonly RealmAccess realm;
|
||||||
|
private readonly MetadataClient metadataClient;
|
||||||
|
|
||||||
|
public BeatmapOnlineChangeIngest(BeatmapUpdater beatmapUpdater, RealmAccess realm, MetadataClient metadataClient)
|
||||||
|
{
|
||||||
|
this.beatmapUpdater = beatmapUpdater;
|
||||||
|
this.realm = realm;
|
||||||
|
this.metadataClient = metadataClient;
|
||||||
|
|
||||||
|
metadataClient.ChangedBeatmapSetsArrived += changesDetected;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void changesDetected(int[] beatmapSetIds)
|
||||||
|
{
|
||||||
|
// May want to batch incoming updates further if the background realm operations ever becomes a concern.
|
||||||
|
realm.Run(r =>
|
||||||
|
{
|
||||||
|
foreach (int id in beatmapSetIds)
|
||||||
|
{
|
||||||
|
var matchingSet = r.All<BeatmapSetInfo>().FirstOrDefault(s => s.OnlineID == id);
|
||||||
|
|
||||||
|
if (matchingSet != null)
|
||||||
|
beatmapUpdater.Queue(matchingSet.ToLive(realm));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
metadataClient.ChangedBeatmapSetsArrived -= changesDetected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -102,6 +102,12 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
beatmapInfo.BeatmapSet.Status = res.BeatmapSet?.Status ?? BeatmapOnlineStatus.None;
|
beatmapInfo.BeatmapSet.Status = res.BeatmapSet?.Status ?? BeatmapOnlineStatus.None;
|
||||||
beatmapInfo.BeatmapSet.OnlineID = res.OnlineBeatmapSetID;
|
beatmapInfo.BeatmapSet.OnlineID = res.OnlineBeatmapSetID;
|
||||||
|
beatmapInfo.BeatmapSet.DateRanked = res.BeatmapSet?.Ranked;
|
||||||
|
beatmapInfo.BeatmapSet.DateSubmitted = res.BeatmapSet?.Submitted;
|
||||||
|
|
||||||
|
beatmapInfo.OnlineMD5Hash = res.MD5Hash;
|
||||||
|
beatmapInfo.LastOnlineUpdate = res.LastUpdated;
|
||||||
|
|
||||||
beatmapInfo.OnlineID = res.OnlineID;
|
beatmapInfo.OnlineID = res.OnlineID;
|
||||||
|
|
||||||
beatmapInfo.Metadata.Author.OnlineID = res.AuthorID;
|
beatmapInfo.Metadata.Author.OnlineID = res.AuthorID;
|
||||||
@ -190,7 +196,8 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
using (var cmd = db.CreateCommand())
|
using (var cmd = db.CreateCommand())
|
||||||
{
|
{
|
||||||
cmd.CommandText = "SELECT beatmapset_id, beatmap_id, approved, user_id FROM osu_beatmaps WHERE checksum = @MD5Hash OR beatmap_id = @OnlineID OR filename = @Path";
|
cmd.CommandText =
|
||||||
|
"SELECT beatmapset_id, beatmap_id, approved, user_id, checksum, last_update FROM osu_beatmaps WHERE checksum = @MD5Hash OR beatmap_id = @OnlineID OR filename = @Path";
|
||||||
|
|
||||||
cmd.Parameters.Add(new SqliteParameter("@MD5Hash", beatmapInfo.MD5Hash));
|
cmd.Parameters.Add(new SqliteParameter("@MD5Hash", beatmapInfo.MD5Hash));
|
||||||
cmd.Parameters.Add(new SqliteParameter("@OnlineID", beatmapInfo.OnlineID));
|
cmd.Parameters.Add(new SqliteParameter("@OnlineID", beatmapInfo.OnlineID));
|
||||||
@ -208,10 +215,13 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
beatmapInfo.BeatmapSet.Status = status;
|
beatmapInfo.BeatmapSet.Status = status;
|
||||||
beatmapInfo.BeatmapSet.OnlineID = reader.GetInt32(0);
|
beatmapInfo.BeatmapSet.OnlineID = reader.GetInt32(0);
|
||||||
|
// TODO: DateSubmitted and DateRanked are not provided by local cache.
|
||||||
beatmapInfo.OnlineID = reader.GetInt32(1);
|
beatmapInfo.OnlineID = reader.GetInt32(1);
|
||||||
|
|
||||||
beatmapInfo.Metadata.Author.OnlineID = reader.GetInt32(3);
|
beatmapInfo.Metadata.Author.OnlineID = reader.GetInt32(3);
|
||||||
|
|
||||||
|
beatmapInfo.OnlineMD5Hash = reader.GetString(4);
|
||||||
|
beatmapInfo.LastOnlineUpdate = reader.GetDateTimeOffset(5);
|
||||||
|
|
||||||
logForModel(set, $"Cached local retrieval for {beatmapInfo}.");
|
logForModel(set, $"Cached local retrieval for {beatmapInfo}.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,16 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public DateTimeOffset DateAdded { get; set; }
|
public DateTimeOffset DateAdded { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The date this beatmap set was first submitted.
|
||||||
|
/// </summary>
|
||||||
|
public DateTimeOffset? DateSubmitted { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The date this beatmap set was ranked.
|
||||||
|
/// </summary>
|
||||||
|
public DateTimeOffset? DateRanked { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public IBeatmapMetadataInfo Metadata => Beatmaps.FirstOrDefault()?.Metadata ?? new BeatmapMetadata();
|
public IBeatmapMetadataInfo Metadata => Beatmaps.FirstOrDefault()?.Metadata ?? new BeatmapMetadata();
|
||||||
|
|
||||||
@ -93,5 +103,7 @@ namespace osu.Game.Beatmaps
|
|||||||
IEnumerable<IBeatmapInfo> IBeatmapSetInfo.Beatmaps => Beatmaps;
|
IEnumerable<IBeatmapInfo> IBeatmapSetInfo.Beatmaps => Beatmaps;
|
||||||
|
|
||||||
IEnumerable<INamedFileUsage> IHasNamedFiles.Files => Files;
|
IEnumerable<INamedFileUsage> IHasNamedFiles.Files => Files;
|
||||||
|
|
||||||
|
public bool AllBeatmapsUpToDate => Beatmaps.All(b => b.MatchesOnlineVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using System.Diagnostics;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using osu.Framework.Extensions.ObjectExtensions;
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
@ -30,21 +31,12 @@ namespace osu.Game.Beatmaps
|
|||||||
onlineLookupQueue = new BeatmapOnlineLookupQueue(api, storage);
|
onlineLookupQueue = new BeatmapOnlineLookupQueue(api, storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Queue a beatmap for background processing.
|
|
||||||
/// </summary>
|
|
||||||
public void Queue(int beatmapSetId)
|
|
||||||
{
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queue a beatmap for background processing.
|
/// Queue a beatmap for background processing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Queue(Live<BeatmapSetInfo> beatmap)
|
public void Queue(Live<BeatmapSetInfo> beatmap)
|
||||||
{
|
{
|
||||||
// For now, just fire off a task.
|
Logger.Log($"Queueing change for local beatmap {beatmap}");
|
||||||
// TODO: Add actual queueing probably.
|
|
||||||
Task.Factory.StartNew(() => beatmap.PerformRead(Process));
|
Task.Factory.StartNew(() => beatmap.PerformRead(Process));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,6 +48,8 @@ namespace osu.Game.Beatmaps
|
|||||||
// Before we use below, we want to invalidate.
|
// Before we use below, we want to invalidate.
|
||||||
workingBeatmapCache.Invalidate(beatmapSet);
|
workingBeatmapCache.Invalidate(beatmapSet);
|
||||||
|
|
||||||
|
// TODO: this call currently uses the local `online.db` lookup.
|
||||||
|
// We probably don't want this to happen after initial import (as the data may be stale).
|
||||||
onlineLookupQueue.Update(beatmapSet);
|
onlineLookupQueue.Update(beatmapSet);
|
||||||
|
|
||||||
foreach (var beatmap in beatmapSet.Beatmaps)
|
foreach (var beatmap in beatmapSet.Beatmaps)
|
||||||
|
@ -224,6 +224,12 @@ namespace osu.Game.Configuration
|
|||||||
|
|
||||||
return new TrackedSettings
|
return new TrackedSettings
|
||||||
{
|
{
|
||||||
|
new TrackedSetting<bool>(OsuSetting.ShowFpsDisplay, state => new SettingDescription(
|
||||||
|
rawValue: state,
|
||||||
|
name: GlobalActionKeyBindingStrings.ToggleFPSCounter,
|
||||||
|
value: state ? CommonStrings.Enabled.ToLower() : CommonStrings.Disabled.ToLower(),
|
||||||
|
shortcut: LookupKeyBindings(GlobalAction.ToggleFPSDisplay))
|
||||||
|
),
|
||||||
new TrackedSetting<bool>(OsuSetting.MouseDisableButtons, disabledState => new SettingDescription(
|
new TrackedSetting<bool>(OsuSetting.MouseDisableButtons, disabledState => new SettingDescription(
|
||||||
rawValue: !disabledState,
|
rawValue: !disabledState,
|
||||||
name: GlobalActionKeyBindingStrings.ToggleGameplayMouseButtons,
|
name: GlobalActionKeyBindingStrings.ToggleGameplayMouseButtons,
|
||||||
|
@ -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;
|
||||||
@ -19,18 +17,18 @@ namespace osu.Game.Database
|
|||||||
where TModel : class, IHasGuidPrimaryKey, ISoftDelete, IEquatable<TModel>, T
|
where TModel : class, IHasGuidPrimaryKey, ISoftDelete, IEquatable<TModel>, T
|
||||||
where T : class
|
where T : class
|
||||||
{
|
{
|
||||||
public Action<Notification> PostNotification { protected get; set; }
|
public Action<Notification>? PostNotification { protected get; set; }
|
||||||
|
|
||||||
public event Action<ArchiveDownloadRequest<T>> DownloadBegan;
|
public event Action<ArchiveDownloadRequest<T>>? DownloadBegan;
|
||||||
|
|
||||||
public event Action<ArchiveDownloadRequest<T>> DownloadFailed;
|
public event Action<ArchiveDownloadRequest<T>>? DownloadFailed;
|
||||||
|
|
||||||
private readonly IModelImporter<TModel> importer;
|
private readonly IModelImporter<TModel> importer;
|
||||||
private readonly IAPIProvider api;
|
private readonly IAPIProvider? api;
|
||||||
|
|
||||||
protected readonly List<ArchiveDownloadRequest<T>> CurrentDownloads = new List<ArchiveDownloadRequest<T>>();
|
protected readonly List<ArchiveDownloadRequest<T>> CurrentDownloads = new List<ArchiveDownloadRequest<T>>();
|
||||||
|
|
||||||
protected ModelDownloader(IModelImporter<TModel> importer, IAPIProvider api)
|
protected ModelDownloader(IModelImporter<TModel> importer, IAPIProvider? api)
|
||||||
{
|
{
|
||||||
this.importer = importer;
|
this.importer = importer;
|
||||||
this.api = api;
|
this.api = api;
|
||||||
@ -87,7 +85,7 @@ namespace osu.Game.Database
|
|||||||
CurrentDownloads.Add(request);
|
CurrentDownloads.Add(request);
|
||||||
PostNotification?.Invoke(notification);
|
PostNotification?.Invoke(notification);
|
||||||
|
|
||||||
api.PerformAsync(request);
|
api?.PerformAsync(request);
|
||||||
|
|
||||||
DownloadBegan?.Invoke(request);
|
DownloadBegan?.Invoke(request);
|
||||||
return true;
|
return true;
|
||||||
@ -105,7 +103,7 @@ namespace osu.Game.Database
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract ArchiveDownloadRequest<T> GetExistingDownload(T model);
|
public abstract ArchiveDownloadRequest<T>? GetExistingDownload(T model);
|
||||||
|
|
||||||
private bool canDownload(T model) => GetExistingDownload(model) == null && api != null;
|
private bool canDownload(T model) => GetExistingDownload(model) == null && api != null;
|
||||||
|
|
||||||
|
@ -61,8 +61,10 @@ namespace osu.Game.Database
|
|||||||
/// 15 2022-07-13 Added LastPlayed to BeatmapInfo.
|
/// 15 2022-07-13 Added LastPlayed to BeatmapInfo.
|
||||||
/// 16 2022-07-15 Removed HasReplay from ScoreInfo.
|
/// 16 2022-07-15 Removed HasReplay from ScoreInfo.
|
||||||
/// 17 2022-07-16 Added CountryCode to RealmUser.
|
/// 17 2022-07-16 Added CountryCode to RealmUser.
|
||||||
|
/// 18 2022-07-19 Added OnlineMD5Hash and LastOnlineUpdate to BeatmapInfo.
|
||||||
|
/// 19 2022-07-19 Added DateSubmitted and DateRanked to BeatmapSetInfo.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const int schema_version = 17;
|
private const int schema_version = 19;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lock object which is held during <see cref="BlockAllOperations"/> sections, blocking realm retrieval during blocking periods.
|
/// Lock object which is held during <see cref="BlockAllOperations"/> sections, blocking realm retrieval during blocking periods.
|
||||||
|
@ -28,7 +28,8 @@ namespace osu.Game.Graphics.Containers
|
|||||||
public class BeatSyncedContainer : Container
|
public class BeatSyncedContainer : Container
|
||||||
{
|
{
|
||||||
private int lastBeat;
|
private int lastBeat;
|
||||||
private TimingControlPoint lastTimingPoint;
|
protected TimingControlPoint LastTimingPoint { get; private set; }
|
||||||
|
protected EffectControlPoint LastEffectPoint { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The amount of time before a beat we should fire <see cref="OnNewBeat(int, TimingControlPoint, EffectControlPoint, ChannelAmplitudes)"/>.
|
/// The amount of time before a beat we should fire <see cref="OnNewBeat(int, TimingControlPoint, EffectControlPoint, ChannelAmplitudes)"/>.
|
||||||
@ -127,7 +128,7 @@ namespace osu.Game.Graphics.Containers
|
|||||||
|
|
||||||
TimeSinceLastBeat = beatLength - TimeUntilNextBeat;
|
TimeSinceLastBeat = beatLength - TimeUntilNextBeat;
|
||||||
|
|
||||||
if (ReferenceEquals(timingPoint, lastTimingPoint) && beatIndex == lastBeat)
|
if (ReferenceEquals(timingPoint, LastTimingPoint) && beatIndex == lastBeat)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// as this event is sometimes used for sound triggers where `BeginDelayedSequence` has no effect, avoid firing it if too far away from the beat.
|
// as this event is sometimes used for sound triggers where `BeginDelayedSequence` has no effect, avoid firing it if too far away from the beat.
|
||||||
@ -139,7 +140,8 @@ namespace osu.Game.Graphics.Containers
|
|||||||
}
|
}
|
||||||
|
|
||||||
lastBeat = beatIndex;
|
lastBeat = beatIndex;
|
||||||
lastTimingPoint = timingPoint;
|
LastTimingPoint = timingPoint;
|
||||||
|
LastEffectPoint = effectPoint;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,21 +3,21 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using osuTK;
|
using System;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio;
|
||||||
|
using osu.Framework.Audio.Sample;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Game.Configuration;
|
|
||||||
using System;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using osu.Framework.Audio;
|
|
||||||
using osu.Framework.Audio.Sample;
|
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.Cursor
|
namespace osu.Game.Graphics.Cursor
|
||||||
{
|
{
|
||||||
@ -35,6 +35,7 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
private Vector2 positionMouseDown;
|
private Vector2 positionMouseDown;
|
||||||
|
|
||||||
private Sample tapSample;
|
private Sample tapSample;
|
||||||
|
private Vector2 lastMovePosition;
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load([NotNull] OsuConfigManager config, [CanBeNull] ScreenshotManager screenshotManager, AudioManager audio)
|
private void load([NotNull] OsuConfigManager config, [CanBeNull] ScreenshotManager screenshotManager, AudioManager audio)
|
||||||
@ -47,16 +48,25 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
tapSample = audio.Samples.Get(@"UI/cursor-tap");
|
tapSample = audio.Samples.Get(@"UI/cursor-tap");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
if (dragRotationState != DragRotationState.NotDragging
|
||||||
|
&& Vector2.Distance(positionMouseDown, lastMovePosition) > 60)
|
||||||
|
{
|
||||||
|
// make the rotation centre point floating.
|
||||||
|
positionMouseDown = Interpolation.ValueAt(0.04f, positionMouseDown, lastMovePosition, 0, Clock.ElapsedFrameTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||||
{
|
{
|
||||||
if (dragRotationState != DragRotationState.NotDragging)
|
if (dragRotationState != DragRotationState.NotDragging)
|
||||||
{
|
{
|
||||||
// make the rotation centre point floating.
|
lastMovePosition = e.MousePosition;
|
||||||
if (Vector2.Distance(positionMouseDown, e.MousePosition) > 60)
|
|
||||||
positionMouseDown = Interpolation.ValueAt(0.005f, positionMouseDown, e.MousePosition, 0, Clock.ElapsedFrameTime);
|
|
||||||
|
|
||||||
var position = e.MousePosition;
|
float distance = Vector2Extensions.Distance(lastMovePosition, positionMouseDown);
|
||||||
float distance = Vector2Extensions.Distance(position, positionMouseDown);
|
|
||||||
|
|
||||||
// don't start rotating until we're moved a minimum distance away from the mouse down location,
|
// don't start rotating until we're moved a minimum distance away from the mouse down location,
|
||||||
// else it can have an annoying effect.
|
// else it can have an annoying effect.
|
||||||
|
302
osu.Game/Graphics/UserInterface/FPSCounter.cs
Normal file
302
osu.Game/Graphics/UserInterface/FPSCounter.cs
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Colour;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Framework.Platform;
|
||||||
|
using osu.Framework.Threading;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.UserInterface
|
||||||
|
{
|
||||||
|
public class FPSCounter : VisibilityContainer, IHasCustomTooltip
|
||||||
|
{
|
||||||
|
private RollingCounter<double> counterUpdateFrameTime = null!;
|
||||||
|
private RollingCounter<double> counterDrawFPS = null!;
|
||||||
|
|
||||||
|
private Container mainContent = null!;
|
||||||
|
|
||||||
|
private Container background = null!;
|
||||||
|
|
||||||
|
private Container counters = null!;
|
||||||
|
|
||||||
|
private const float idle_background_alpha = 0.4f;
|
||||||
|
|
||||||
|
private readonly BindableBool showFpsDisplay = new BindableBool(true);
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OsuColour colours { get; set; } = null!;
|
||||||
|
|
||||||
|
public FPSCounter()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuConfigManager config)
|
||||||
|
{
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
mainContent = new Container
|
||||||
|
{
|
||||||
|
Alpha = 0,
|
||||||
|
Height = 26,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
background = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
CornerRadius = 5,
|
||||||
|
CornerExponent = 5f,
|
||||||
|
Masking = true,
|
||||||
|
Alpha = idle_background_alpha,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
Colour = colours.Gray0,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
counters = new Container
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
counterUpdateFrameTime = new FrameTimeCounter
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
Margin = new MarginPadding(1),
|
||||||
|
Y = -2,
|
||||||
|
},
|
||||||
|
counterDrawFPS = new FramesPerSecondCounter
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
Margin = new MarginPadding(2),
|
||||||
|
Y = 10,
|
||||||
|
Scale = new Vector2(0.8f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
config.BindWith(OsuSetting.ShowFpsDisplay, showFpsDisplay);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
displayTemporarily();
|
||||||
|
|
||||||
|
showFpsDisplay.BindValueChanged(showFps =>
|
||||||
|
{
|
||||||
|
State.Value = showFps.NewValue ? Visibility.Visible : Visibility.Hidden;
|
||||||
|
if (showFps.NewValue)
|
||||||
|
displayTemporarily();
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
State.BindValueChanged(state => showFpsDisplay.Value = state.NewValue == Visibility.Visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopIn() => this.FadeIn(100);
|
||||||
|
|
||||||
|
protected override void PopOut() => this.FadeOut(100);
|
||||||
|
|
||||||
|
protected override bool OnHover(HoverEvent e)
|
||||||
|
{
|
||||||
|
background.FadeTo(1, 200);
|
||||||
|
displayTemporarily();
|
||||||
|
return base.OnHover(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnHoverLost(HoverLostEvent e)
|
||||||
|
{
|
||||||
|
background.FadeTo(idle_background_alpha, 200);
|
||||||
|
displayTemporarily();
|
||||||
|
base.OnHoverLost(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool isDisplayed;
|
||||||
|
|
||||||
|
private ScheduledDelegate? fadeOutDelegate;
|
||||||
|
|
||||||
|
private double aimDrawFPS;
|
||||||
|
private double aimUpdateFPS;
|
||||||
|
|
||||||
|
private void displayTemporarily()
|
||||||
|
{
|
||||||
|
if (!isDisplayed)
|
||||||
|
{
|
||||||
|
mainContent.FadeTo(1, 300, Easing.OutQuint);
|
||||||
|
isDisplayed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fadeOutDelegate?.Cancel();
|
||||||
|
fadeOutDelegate = null;
|
||||||
|
|
||||||
|
if (!IsHovered)
|
||||||
|
{
|
||||||
|
fadeOutDelegate = Scheduler.AddDelayed(() =>
|
||||||
|
{
|
||||||
|
mainContent.FadeTo(0, 300, Easing.OutQuint);
|
||||||
|
isDisplayed = false;
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private GameHost gameHost { get; set; } = null!;
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
mainContent.Width = Math.Max(mainContent.Width, counters.DrawWidth);
|
||||||
|
|
||||||
|
// Handle the case where the window has become inactive or the user changed the
|
||||||
|
// frame limiter (we want to show the FPS as it's changing, even if it isn't an outlier).
|
||||||
|
bool aimRatesChanged = updateAimFPS();
|
||||||
|
|
||||||
|
// TODO: this is wrong (elapsed clock time, not actual run time).
|
||||||
|
double newUpdateFrameTime = gameHost.UpdateThread.Clock.ElapsedFrameTime;
|
||||||
|
double newDrawFrameTime = gameHost.DrawThread.Clock.ElapsedFrameTime;
|
||||||
|
double newDrawFps = gameHost.DrawThread.Clock.FramesPerSecond;
|
||||||
|
|
||||||
|
const double spike_time_ms = 20;
|
||||||
|
|
||||||
|
bool hasUpdateSpike = counterUpdateFrameTime.Current.Value < spike_time_ms && newUpdateFrameTime > spike_time_ms;
|
||||||
|
// use elapsed frame time rather then FramesPerSecond to better catch stutter frames.
|
||||||
|
bool hasDrawSpike = counterDrawFPS.Current.Value > (1000 / spike_time_ms) && newDrawFrameTime > spike_time_ms;
|
||||||
|
|
||||||
|
// If the frame time spikes up, make sure it shows immediately on the counter.
|
||||||
|
if (hasUpdateSpike)
|
||||||
|
counterUpdateFrameTime.SetCountWithoutRolling(newUpdateFrameTime);
|
||||||
|
else
|
||||||
|
counterUpdateFrameTime.Current.Value = newUpdateFrameTime;
|
||||||
|
|
||||||
|
if (hasDrawSpike)
|
||||||
|
// show spike time using raw elapsed value, to account for `FramesPerSecond` being so averaged spike frames don't show.
|
||||||
|
counterDrawFPS.SetCountWithoutRolling(1000 / newDrawFrameTime);
|
||||||
|
else
|
||||||
|
counterDrawFPS.Current.Value = newDrawFps;
|
||||||
|
|
||||||
|
counterDrawFPS.Colour = getColour(counterDrawFPS.DisplayedCount / aimDrawFPS);
|
||||||
|
|
||||||
|
double displayedUpdateFPS = 1000 / counterUpdateFrameTime.DisplayedCount;
|
||||||
|
counterUpdateFrameTime.Colour = getColour(displayedUpdateFPS / aimUpdateFPS);
|
||||||
|
|
||||||
|
bool hasSignificantChanges = aimRatesChanged
|
||||||
|
|| hasDrawSpike
|
||||||
|
|| hasUpdateSpike
|
||||||
|
|| counterDrawFPS.DisplayedCount < aimDrawFPS * 0.8
|
||||||
|
|| displayedUpdateFPS < aimUpdateFPS * 0.8;
|
||||||
|
|
||||||
|
if (hasSignificantChanges)
|
||||||
|
displayTemporarily();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool updateAimFPS()
|
||||||
|
{
|
||||||
|
if (gameHost.UpdateThread.Clock.Throttling)
|
||||||
|
{
|
||||||
|
double newAimDrawFPS = gameHost.DrawThread.Clock.MaximumUpdateHz;
|
||||||
|
double newAimUpdateFPS = gameHost.UpdateThread.Clock.MaximumUpdateHz;
|
||||||
|
|
||||||
|
if (aimDrawFPS != newAimDrawFPS || aimUpdateFPS != newAimUpdateFPS)
|
||||||
|
{
|
||||||
|
aimDrawFPS = newAimDrawFPS;
|
||||||
|
aimUpdateFPS = newAimUpdateFPS;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double newAimFPS = gameHost.InputThread.Clock.MaximumUpdateHz;
|
||||||
|
|
||||||
|
if (aimDrawFPS != newAimFPS || aimUpdateFPS != newAimFPS)
|
||||||
|
{
|
||||||
|
aimUpdateFPS = aimDrawFPS = newAimFPS;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ColourInfo getColour(double performanceRatio)
|
||||||
|
{
|
||||||
|
if (performanceRatio < 0.5f)
|
||||||
|
return Interpolation.ValueAt(performanceRatio, colours.Red, colours.Orange2, 0, 0.5);
|
||||||
|
|
||||||
|
return Interpolation.ValueAt(performanceRatio, colours.Orange2, colours.Lime0, 0.5, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ITooltip GetCustomTooltip() => new FPSCounterTooltip();
|
||||||
|
|
||||||
|
public object TooltipContent => this;
|
||||||
|
|
||||||
|
public class FramesPerSecondCounter : RollingCounter<double>
|
||||||
|
{
|
||||||
|
protected override double RollingDuration => 1000;
|
||||||
|
|
||||||
|
protected override OsuSpriteText CreateSpriteText()
|
||||||
|
{
|
||||||
|
return new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
Font = OsuFont.Default.With(fixedWidth: true, size: 16, weight: FontWeight.SemiBold),
|
||||||
|
Spacing = new Vector2(-2),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override LocalisableString FormatCount(double count)
|
||||||
|
{
|
||||||
|
return $"{count:#,0}fps";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FrameTimeCounter : RollingCounter<double>
|
||||||
|
{
|
||||||
|
protected override double RollingDuration => 1000;
|
||||||
|
|
||||||
|
protected override OsuSpriteText CreateSpriteText()
|
||||||
|
{
|
||||||
|
return new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
Font = OsuFont.Default.With(fixedWidth: true, size: 16, weight: FontWeight.SemiBold),
|
||||||
|
Spacing = new Vector2(-1),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override LocalisableString FormatCount(double count)
|
||||||
|
{
|
||||||
|
if (count < 1)
|
||||||
|
return $"{count:N1}ms";
|
||||||
|
|
||||||
|
return $"{count:N0}ms";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
97
osu.Game/Graphics/UserInterface/FPSCounterTooltip.cs
Normal file
97
osu.Game/Graphics/UserInterface/FPSCounterTooltip.cs
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Platform;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.UserInterface
|
||||||
|
{
|
||||||
|
public class FPSCounterTooltip : CompositeDrawable, ITooltip
|
||||||
|
{
|
||||||
|
private OsuTextFlowContainer textFlow = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private GameHost gameHost { get; set; } = null!;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
CornerRadius = 15;
|
||||||
|
Masking = true;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
Colour = colours.Gray1,
|
||||||
|
Alpha = 1,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
new OsuTextFlowContainer(cp =>
|
||||||
|
{
|
||||||
|
cp.Font = OsuFont.Default.With(weight: FontWeight.SemiBold);
|
||||||
|
})
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
TextAnchor = Anchor.TopRight,
|
||||||
|
Margin = new MarginPadding { Left = 5, Vertical = 10 },
|
||||||
|
Text = string.Join('\n', gameHost.Threads.Select(t => t.Name))
|
||||||
|
},
|
||||||
|
textFlow = new OsuTextFlowContainer(cp =>
|
||||||
|
{
|
||||||
|
cp.Font = OsuFont.Default.With(fixedWidth: true, weight: FontWeight.Regular);
|
||||||
|
cp.Spacing = new Vector2(-1);
|
||||||
|
})
|
||||||
|
{
|
||||||
|
Width = 190,
|
||||||
|
Margin = new MarginPadding { Left = 35, Right = 10, Vertical = 10 },
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
TextAnchor = Anchor.TopRight,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private int lastUpdate;
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
int currentSecond = (int)(Clock.CurrentTime / 100);
|
||||||
|
|
||||||
|
if (currentSecond != lastUpdate)
|
||||||
|
{
|
||||||
|
lastUpdate = currentSecond;
|
||||||
|
|
||||||
|
textFlow.Clear();
|
||||||
|
|
||||||
|
foreach (var thread in gameHost.Threads)
|
||||||
|
{
|
||||||
|
var clock = thread.Clock;
|
||||||
|
|
||||||
|
string maximum = clock.Throttling
|
||||||
|
? $"/{(clock.MaximumUpdateHz > 0 && clock.MaximumUpdateHz < 10000 ? clock.MaximumUpdateHz.ToString("0") : "∞"),4}"
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
textFlow.AddParagraph($"{clock.FramesPerSecond:0}{maximum}fps ({clock.ElapsedFrameTime:0.00}ms)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetContent(object content)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Move(Vector2 pos)
|
||||||
|
{
|
||||||
|
Position = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -45,6 +45,7 @@ namespace osu.Game.Input.Bindings
|
|||||||
new KeyBinding(InputKey.F9, GlobalAction.ToggleSocial),
|
new KeyBinding(InputKey.F9, GlobalAction.ToggleSocial),
|
||||||
new KeyBinding(InputKey.F10, GlobalAction.ToggleGameplayMouseButtons),
|
new KeyBinding(InputKey.F10, GlobalAction.ToggleGameplayMouseButtons),
|
||||||
new KeyBinding(InputKey.F12, GlobalAction.TakeScreenshot),
|
new KeyBinding(InputKey.F12, GlobalAction.TakeScreenshot),
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.F }, GlobalAction.ToggleFPSDisplay),
|
||||||
|
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings),
|
new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.T }, GlobalAction.ToggleToolbar),
|
new KeyBinding(new[] { InputKey.Control, InputKey.T }, GlobalAction.ToggleToolbar),
|
||||||
@ -328,5 +329,8 @@ namespace osu.Game.Input.Bindings
|
|||||||
|
|
||||||
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorTapForBPM))]
|
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorTapForBPM))]
|
||||||
EditorTapForBPM,
|
EditorTapForBPM,
|
||||||
|
|
||||||
|
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleFPSCounter))]
|
||||||
|
ToggleFPSDisplay,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -274,6 +274,11 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString ToggleSkinEditor => new TranslatableString(getKey(@"toggle_skin_editor"), @"Toggle skin editor");
|
public static LocalisableString ToggleSkinEditor => new TranslatableString(getKey(@"toggle_skin_editor"), @"Toggle skin editor");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Toggle FPS counter"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString ToggleFPSCounter => new TranslatableString(getKey(@"toggle_fps_counter"), @"Toggle FPS counter");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Previous volume meter"
|
/// "Previous volume meter"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -11,15 +11,16 @@ namespace osu.Game.Online.API.Requests
|
|||||||
{
|
{
|
||||||
public class GetWikiRequest : APIRequest<APIWikiPage>
|
public class GetWikiRequest : APIRequest<APIWikiPage>
|
||||||
{
|
{
|
||||||
private readonly string path;
|
public readonly string Path;
|
||||||
|
|
||||||
private readonly Language language;
|
private readonly Language language;
|
||||||
|
|
||||||
public GetWikiRequest(string path, Language language = Language.en)
|
public GetWikiRequest(string path, Language language = Language.en)
|
||||||
{
|
{
|
||||||
this.path = path;
|
Path = path;
|
||||||
this.language = language;
|
this.language = language;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string Target => $"wiki/{language.ToCultureCode()}/{path}";
|
protected override string Target => $"wiki/{language.ToCultureCode()}/{Path}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,6 +81,9 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
[JsonProperty(@"max_combo")]
|
[JsonProperty(@"max_combo")]
|
||||||
public int? MaxCombo { get; set; }
|
public int? MaxCombo { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(@"last_updated")]
|
||||||
|
public DateTimeOffset LastUpdated { get; set; }
|
||||||
|
|
||||||
public double BPM { get; set; }
|
public double BPM { get; set; }
|
||||||
|
|
||||||
#region Implementation of IBeatmapInfo
|
#region Implementation of IBeatmapInfo
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// 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.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
|
||||||
@ -11,5 +13,13 @@ namespace osu.Game.Online.Metadata
|
|||||||
public abstract Task BeatmapSetsUpdated(BeatmapUpdates updates);
|
public abstract Task BeatmapSetsUpdated(BeatmapUpdates updates);
|
||||||
|
|
||||||
public abstract Task<BeatmapUpdates> GetChangesSince(int queueId);
|
public abstract Task<BeatmapUpdates> GetChangesSince(int queueId);
|
||||||
|
|
||||||
|
public Action<int[]>? ChangedBeatmapSetsArrived;
|
||||||
|
|
||||||
|
protected Task ProcessChanges(int[] beatmapSetIDs)
|
||||||
|
{
|
||||||
|
ChangedBeatmapSetsArrived?.Invoke(beatmapSetIDs.Distinct().ToArray());
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ using Microsoft.AspNetCore.SignalR.Client;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
|
|
||||||
@ -15,7 +14,6 @@ namespace osu.Game.Online.Metadata
|
|||||||
{
|
{
|
||||||
public class OnlineMetadataClient : MetadataClient
|
public class OnlineMetadataClient : MetadataClient
|
||||||
{
|
{
|
||||||
private readonly BeatmapUpdater beatmapUpdater;
|
|
||||||
private readonly string endpoint;
|
private readonly string endpoint;
|
||||||
|
|
||||||
private IHubClientConnector? connector;
|
private IHubClientConnector? connector;
|
||||||
@ -24,9 +22,8 @@ namespace osu.Game.Online.Metadata
|
|||||||
|
|
||||||
private HubConnection? connection => connector?.CurrentConnection;
|
private HubConnection? connection => connector?.CurrentConnection;
|
||||||
|
|
||||||
public OnlineMetadataClient(EndpointConfiguration endpoints, BeatmapUpdater beatmapUpdater)
|
public OnlineMetadataClient(EndpointConfiguration endpoints)
|
||||||
{
|
{
|
||||||
this.beatmapUpdater = beatmapUpdater;
|
|
||||||
endpoint = endpoints.MetadataEndpointUrl;
|
endpoint = endpoints.MetadataEndpointUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,17 +99,6 @@ namespace osu.Game.Online.Metadata
|
|||||||
await ProcessChanges(updates.BeatmapSetIDs);
|
await ProcessChanges(updates.BeatmapSetIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Task ProcessChanges(int[] beatmapSetIDs)
|
|
||||||
{
|
|
||||||
foreach (int id in beatmapSetIDs)
|
|
||||||
{
|
|
||||||
Logger.Log($"Processing {id}...");
|
|
||||||
beatmapUpdater.Queue(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Task<BeatmapUpdates> GetChangesSince(int queueId)
|
public override Task<BeatmapUpdates> GetChangesSince(int queueId)
|
||||||
{
|
{
|
||||||
if (connector?.IsConnected.Value != true)
|
if (connector?.IsConnected.Value != true)
|
||||||
|
@ -159,6 +159,8 @@ namespace osu.Game
|
|||||||
|
|
||||||
protected FirstRunSetupOverlay FirstRunOverlay { get; private set; }
|
protected FirstRunSetupOverlay FirstRunOverlay { get; private set; }
|
||||||
|
|
||||||
|
private FPSCounter fpsCounter;
|
||||||
|
|
||||||
private VolumeOverlay volume;
|
private VolumeOverlay volume;
|
||||||
|
|
||||||
private OsuLogo osuLogo;
|
private OsuLogo osuLogo;
|
||||||
@ -814,6 +816,13 @@ namespace osu.Game
|
|||||||
ScreenStack.ScreenPushed += screenPushed;
|
ScreenStack.ScreenPushed += screenPushed;
|
||||||
ScreenStack.ScreenExited += screenExited;
|
ScreenStack.ScreenExited += screenExited;
|
||||||
|
|
||||||
|
loadComponentSingleFile(fpsCounter = new FPSCounter
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomRight,
|
||||||
|
Origin = Anchor.BottomRight,
|
||||||
|
Margin = new MarginPadding(5),
|
||||||
|
}, topMostOverlayContent.Add);
|
||||||
|
|
||||||
if (!args?.Any(a => a == @"--no-version-overlay") ?? true)
|
if (!args?.Any(a => a == @"--no-version-overlay") ?? true)
|
||||||
loadComponentSingleFile(versionManager = new VersionManager { Depth = int.MinValue }, ScreenContainer.Add);
|
loadComponentSingleFile(versionManager = new VersionManager { Depth = int.MinValue }, ScreenContainer.Add);
|
||||||
|
|
||||||
@ -1114,6 +1123,10 @@ namespace osu.Game
|
|||||||
|
|
||||||
switch (e.Action)
|
switch (e.Action)
|
||||||
{
|
{
|
||||||
|
case GlobalAction.ToggleFPSDisplay:
|
||||||
|
fpsCounter.ToggleVisibility();
|
||||||
|
return true;
|
||||||
|
|
||||||
case GlobalAction.ToggleSkinEditor:
|
case GlobalAction.ToggleSkinEditor:
|
||||||
skinEditor.ToggleVisibility();
|
skinEditor.ToggleVisibility();
|
||||||
return true;
|
return true;
|
||||||
|
@ -17,7 +17,6 @@ using osu.Framework.Development;
|
|||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Performance;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Input.Handlers;
|
using osu.Framework.Input.Handlers;
|
||||||
@ -192,8 +191,6 @@ namespace osu.Game
|
|||||||
|
|
||||||
private DependencyContainer dependencies;
|
private DependencyContainer dependencies;
|
||||||
|
|
||||||
private Bindable<bool> fpsDisplayVisible;
|
|
||||||
|
|
||||||
private readonly BindableNumber<double> globalTrackVolumeAdjust = new BindableNumber<double>(global_track_volume_adjust);
|
private readonly BindableNumber<double> globalTrackVolumeAdjust = new BindableNumber<double>(global_track_volume_adjust);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -287,7 +284,9 @@ namespace osu.Game
|
|||||||
|
|
||||||
dependencies.CacheAs(spectatorClient = new OnlineSpectatorClient(endpoints));
|
dependencies.CacheAs(spectatorClient = new OnlineSpectatorClient(endpoints));
|
||||||
dependencies.CacheAs(multiplayerClient = new OnlineMultiplayerClient(endpoints));
|
dependencies.CacheAs(multiplayerClient = new OnlineMultiplayerClient(endpoints));
|
||||||
dependencies.CacheAs(metadataClient = new OnlineMetadataClient(endpoints, beatmapUpdater));
|
dependencies.CacheAs(metadataClient = new OnlineMetadataClient(endpoints));
|
||||||
|
|
||||||
|
AddInternal(new BeatmapOnlineChangeIngest(beatmapUpdater, realm, metadataClient));
|
||||||
|
|
||||||
BeatmapManager.ProcessBeatmap = set => beatmapUpdater.Process(set);
|
BeatmapManager.ProcessBeatmap = set => beatmapUpdater.Process(set);
|
||||||
|
|
||||||
@ -404,19 +403,6 @@ namespace osu.Game
|
|||||||
AddFont(Resources, @"Fonts/Venera/Venera-Black");
|
AddFont(Resources, @"Fonts/Venera/Venera-Black");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
// TODO: This is temporary until we reimplement the local FPS display.
|
|
||||||
// It's just to allow end-users to access the framework FPS display without knowing the shortcut key.
|
|
||||||
fpsDisplayVisible = LocalConfig.GetBindable<bool>(OsuSetting.ShowFpsDisplay);
|
|
||||||
fpsDisplayVisible.ValueChanged += visible => { FrameStatistics.Value = visible.NewValue ? FrameStatisticsMode.Minimal : FrameStatisticsMode.None; };
|
|
||||||
fpsDisplayVisible.TriggerChange();
|
|
||||||
|
|
||||||
FrameStatistics.ValueChanged += e => fpsDisplayVisible.Value = e.NewValue != FrameStatisticsMode.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) =>
|
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) =>
|
||||||
dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ using osuTK;
|
|||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Framework.Extensions.LocalisationExtensions;
|
using osu.Framework.Extensions.LocalisationExtensions;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Game.Resources.Localisation.Web;
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.BeatmapSet.Scores
|
namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||||
@ -38,8 +39,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
|||||||
|
|
||||||
private readonly FillFlowContainer backgroundFlow;
|
private readonly FillFlowContainer backgroundFlow;
|
||||||
|
|
||||||
private Color4 highAccuracyColour;
|
|
||||||
|
|
||||||
public ScoreTable()
|
public ScoreTable()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
@ -57,12 +56,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
highAccuracyColour = colours.GreenLight;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The statistics that appear in the table, in order of appearance.
|
/// The statistics that appear in the table, in order of appearance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -158,12 +151,10 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
|||||||
Current = scoreManager.GetBindableTotalScoreString(score),
|
Current = scoreManager.GetBindableTotalScoreString(score),
|
||||||
Font = OsuFont.GetFont(size: text_size, weight: index == 0 ? FontWeight.Bold : FontWeight.Medium)
|
Font = OsuFont.GetFont(size: text_size, weight: index == 0 ? FontWeight.Bold : FontWeight.Medium)
|
||||||
},
|
},
|
||||||
new OsuSpriteText
|
new StatisticText(score.Accuracy, 1, showTooltip: false)
|
||||||
{
|
{
|
||||||
Margin = new MarginPadding { Right = horizontal_inset },
|
Margin = new MarginPadding { Right = horizontal_inset },
|
||||||
Text = score.DisplayAccuracy,
|
Text = score.DisplayAccuracy,
|
||||||
Font = OsuFont.GetFont(size: text_size),
|
|
||||||
Colour = score.Accuracy == 1 ? highAccuracyColour : Color4.White
|
|
||||||
},
|
},
|
||||||
new UpdateableFlag(score.User.CountryCode)
|
new UpdateableFlag(score.User.CountryCode)
|
||||||
{
|
{
|
||||||
@ -171,14 +162,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
|||||||
ShowPlaceholderOnUnknown = false,
|
ShowPlaceholderOnUnknown = false,
|
||||||
},
|
},
|
||||||
username,
|
username,
|
||||||
new OsuSpriteText
|
|
||||||
{
|
|
||||||
Text = score.MaxCombo.ToLocalisableString(@"0\x"),
|
|
||||||
Font = OsuFont.GetFont(size: text_size),
|
|
||||||
#pragma warning disable 618
|
#pragma warning disable 618
|
||||||
Colour = score.MaxCombo == score.BeatmapInfo.MaxCombo ? highAccuracyColour : Color4.White
|
new StatisticText(score.MaxCombo, score.BeatmapInfo.MaxCombo, @"0\x"),
|
||||||
#pragma warning restore 618
|
#pragma warning restore 618
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var availableStatistics = score.GetStatisticsForDisplay().ToDictionary(tuple => tuple.Result);
|
var availableStatistics = score.GetStatisticsForDisplay().ToDictionary(tuple => tuple.Result);
|
||||||
@ -188,23 +174,13 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
|||||||
if (!availableStatistics.TryGetValue(result.result, out var stat))
|
if (!availableStatistics.TryGetValue(result.result, out var stat))
|
||||||
stat = new HitResultDisplayStatistic(result.result, 0, null, result.displayName);
|
stat = new HitResultDisplayStatistic(result.result, 0, null, result.displayName);
|
||||||
|
|
||||||
content.Add(new OsuSpriteText
|
content.Add(new StatisticText(stat.Count, stat.MaxCount, @"N0") { Colour = stat.Count == 0 ? Color4.Gray : Color4.White });
|
||||||
{
|
|
||||||
Text = stat.MaxCount == null ? stat.Count.ToLocalisableString(@"N0") : (LocalisableString)$"{stat.Count}/{stat.MaxCount}",
|
|
||||||
Font = OsuFont.GetFont(size: text_size),
|
|
||||||
Colour = stat.Count == 0 ? Color4.Gray : Color4.White
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showPerformancePoints)
|
if (showPerformancePoints)
|
||||||
{
|
{
|
||||||
Debug.Assert(score.PP != null);
|
Debug.Assert(score.PP != null);
|
||||||
|
content.Add(new StatisticText(score.PP.Value, format: @"N0"));
|
||||||
content.Add(new OsuSpriteText
|
|
||||||
{
|
|
||||||
Text = score.PP.ToLocalisableString(@"N0"),
|
|
||||||
Font = OsuFont.GetFont(size: text_size)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
content.Add(new ScoreboardTime(score.Date, text_size)
|
content.Add(new ScoreboardTime(score.Date, text_size)
|
||||||
@ -243,5 +219,31 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
|||||||
Colour = colourProvider.Foreground1;
|
Colour = colourProvider.Foreground1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class StatisticText : OsuSpriteText, IHasTooltip
|
||||||
|
{
|
||||||
|
private readonly double count;
|
||||||
|
private readonly double? maxCount;
|
||||||
|
private readonly bool showTooltip;
|
||||||
|
|
||||||
|
public LocalisableString TooltipText => maxCount == null || !showTooltip ? string.Empty : $"{count}/{maxCount}";
|
||||||
|
|
||||||
|
public StatisticText(double count, double? maxCount = null, string format = null, bool showTooltip = true)
|
||||||
|
{
|
||||||
|
this.count = count;
|
||||||
|
this.maxCount = maxCount;
|
||||||
|
this.showTooltip = showTooltip;
|
||||||
|
|
||||||
|
Text = count.ToLocalisableString(format);
|
||||||
|
Font = OsuFont.GetFont(size: text_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
if (count == maxCount)
|
||||||
|
Colour = colours.GreenLight;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,6 +222,8 @@ namespace osu.Game.Overlays.Mods
|
|||||||
globalAvailableMods.BindTo(game.AvailableMods);
|
globalAvailableMods.BindTo(game.AvailableMods);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ModSettingChangeTracker? modSettingChangeTracker;
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
// this is called before base call so that the mod state is populated early, and the transition in `PopIn()` can play out properly.
|
// this is called before base call so that the mod state is populated early, and the transition in `PopIn()` can play out properly.
|
||||||
@ -238,9 +240,17 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
SelectedMods.BindValueChanged(val =>
|
SelectedMods.BindValueChanged(val =>
|
||||||
{
|
{
|
||||||
|
modSettingChangeTracker?.Dispose();
|
||||||
|
|
||||||
updateMultiplier();
|
updateMultiplier();
|
||||||
updateCustomisation(val);
|
updateCustomisation(val);
|
||||||
updateFromExternalSelection();
|
updateFromExternalSelection();
|
||||||
|
|
||||||
|
if (AllowCustomisation)
|
||||||
|
{
|
||||||
|
modSettingChangeTracker = new ModSettingChangeTracker(val.NewValue);
|
||||||
|
modSettingChangeTracker.SettingChanged += _ => updateMultiplier();
|
||||||
|
}
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
customisationVisible.BindValueChanged(_ => updateCustomisationVisualState(), true);
|
customisationVisible.BindValueChanged(_ => updateCustomisationVisualState(), true);
|
||||||
|
@ -100,6 +100,11 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private void onPathChanged(ValueChangedEvent<string> e)
|
private void onPathChanged(ValueChangedEvent<string> e)
|
||||||
{
|
{
|
||||||
|
// the path could change as a result of redirecting to a newer location of the same page.
|
||||||
|
// we already have the correct wiki data, so we can safely return here.
|
||||||
|
if (e.NewValue == wikiData.Value?.Path)
|
||||||
|
return;
|
||||||
|
|
||||||
cancellationToken?.Cancel();
|
cancellationToken?.Cancel();
|
||||||
request?.Cancel();
|
request?.Cancel();
|
||||||
|
|
||||||
@ -121,6 +126,7 @@ namespace osu.Game.Overlays
|
|||||||
private void onSuccess(APIWikiPage response)
|
private void onSuccess(APIWikiPage response)
|
||||||
{
|
{
|
||||||
wikiData.Value = response;
|
wikiData.Value = response;
|
||||||
|
path.Value = response.Path;
|
||||||
|
|
||||||
if (response.Layout == index_path)
|
if (response.Layout == index_path)
|
||||||
{
|
{
|
||||||
|
@ -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.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
@ -29,7 +27,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A function that can extract the current value of this setting from a beatmap difficulty for display purposes.
|
/// A function that can extract the current value of this setting from a beatmap difficulty for display purposes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<IBeatmapDifficultyInfo, float> ReadCurrentFromDifficulty;
|
public Func<IBeatmapDifficultyInfo, float>? ReadCurrentFromDifficulty;
|
||||||
|
|
||||||
public float Precision
|
public float Precision
|
||||||
{
|
{
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
{
|
{
|
||||||
public interface IApplicableToAudio : IApplicableToTrack, IApplicableToSample
|
public interface IApplicableToAudio : IApplicableToTrack, IApplicableToSample
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
|
@ -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 osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
|
@ -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 osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
@ -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.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
@ -45,7 +43,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly ModCreatedUser User;
|
public readonly ModCreatedUser User;
|
||||||
|
|
||||||
public ModReplayData(Replay replay, ModCreatedUser user = null)
|
public ModReplayData(Replay replay, ModCreatedUser? user = null)
|
||||||
{
|
{
|
||||||
Replay = replay;
|
Replay = replay;
|
||||||
User = user ?? new ModCreatedUser();
|
User = user ?? new ModCreatedUser();
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
|
@ -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.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
@ -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;
|
||||||
@ -117,7 +115,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public virtual Type[] IncompatibleMods => Array.Empty<Type>();
|
public virtual Type[] IncompatibleMods => Array.Empty<Type>();
|
||||||
|
|
||||||
private IReadOnlyList<IBindable> settingsBacking;
|
private IReadOnlyList<IBindable>? settingsBacking;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A list of the all <see cref="IBindable"/> settings within this mod.
|
/// A list of the all <see cref="IBindable"/> settings within this mod.
|
||||||
@ -128,6 +126,11 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
.Cast<IBindable>()
|
.Cast<IBindable>()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether all settings in this mod are set to their default state.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual bool UsesDefaultConfiguration => Settings.All(s => s.IsDefault);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a copy of this <see cref="Mod"/> initialised to a default state.
|
/// Creates a copy of this <see cref="Mod"/> initialised to a default state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -216,8 +219,8 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
|
|
||||||
public bool Equals(IBindable x, IBindable y)
|
public bool Equals(IBindable x, IBindable y)
|
||||||
{
|
{
|
||||||
object xValue = x?.GetUnderlyingSettingValue();
|
object xValue = x.GetUnderlyingSettingValue();
|
||||||
object yValue = y?.GetUnderlyingSettingValue();
|
object yValue = y.GetUnderlyingSettingValue();
|
||||||
|
|
||||||
return EqualityComparer<object>.Default.Equals(xValue, yValue);
|
return EqualityComparer<object>.Default.Equals(xValue, yValue);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
@ -79,7 +77,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
// Apply a fixed rate change when missing, allowing the player to catch up when the rate is too fast.
|
// Apply a fixed rate change when missing, allowing the player to catch up when the rate is too fast.
|
||||||
private const double rate_change_on_miss = 0.95d;
|
private const double rate_change_on_miss = 0.95d;
|
||||||
|
|
||||||
private IAdjustableAudioComponent track;
|
private IAdjustableAudioComponent? track;
|
||||||
private double targetRate = 1d;
|
private double targetRate = 1d;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
@ -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.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
@ -11,7 +9,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
{
|
{
|
||||||
public abstract class ModBlockFail : Mod, IApplicableFailOverride, IApplicableToHUD, IReadFromConfig
|
public abstract class ModBlockFail : Mod, IApplicableFailOverride, IApplicableToHUD, IReadFromConfig
|
||||||
{
|
{
|
||||||
private Bindable<bool> showHealthBar;
|
private readonly Bindable<bool> showHealthBar = new Bindable<bool>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// We never fail, 'yo.
|
/// We never fail, 'yo.
|
||||||
@ -22,7 +20,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
|
|
||||||
public void ReadFromConfig(OsuConfigManager config)
|
public void ReadFromConfig(OsuConfigManager config)
|
||||||
{
|
{
|
||||||
showHealthBar = config.GetBindable<bool>(OsuSetting.ShowHealthDisplayWhenCantFail);
|
config.BindWith(OsuSetting.ShowHealthDisplayWhenCantFail, showHealthBar);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ApplyToHUD(HUDOverlay overlay)
|
public void ApplyToHUD(HUDOverlay overlay)
|
||||||
|
@ -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.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user