mirror of
https://github.com/ppy/osu.git
synced 2024-12-15 02:42:54 +08:00
Merge branch 'master' into mania-pooling
This commit is contained in:
commit
9ede358e7e
@ -52,6 +52,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.422.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.422.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.510.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.513.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -28,10 +28,12 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
catchPlayfield.CatcherArea.MovableCatcher.CatchFruitOnPlate = false;
|
catchPlayfield.CatcherArea.MovableCatcher.CatchFruitOnPlate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
||||||
{
|
{
|
||||||
base.ApplyNormalVisibilityState(hitObject, state);
|
|
||||||
|
|
||||||
if (!(hitObject is DrawableCatchHitObject catchDrawable))
|
if (!(hitObject is DrawableCatchHitObject catchDrawable))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -54,7 +56,7 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
var offset = hitObject.TimePreempt * fade_out_offset_multiplier;
|
var offset = hitObject.TimePreempt * fade_out_offset_multiplier;
|
||||||
var duration = offset - hitObject.TimePreempt * fade_out_duration_multiplier;
|
var duration = offset - hitObject.TimePreempt * fade_out_duration_multiplier;
|
||||||
|
|
||||||
using (drawable.BeginAbsoluteSequence(hitObject.StartTime - offset, true))
|
using (drawable.BeginAbsoluteSequence(hitObject.StartTime - offset))
|
||||||
drawable.FadeOut(duration);
|
drawable.FadeOut(duration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
|||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
explosion = new LegacyRollingCounter(skin, LegacyFont.Combo)
|
explosion = new LegacyRollingCounter(LegacyFont.Combo)
|
||||||
{
|
{
|
||||||
Alpha = 0.65f,
|
Alpha = 0.65f,
|
||||||
Blending = BlendingParameters.Additive,
|
Blending = BlendingParameters.Additive,
|
||||||
@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
|||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Scale = new Vector2(1.5f),
|
Scale = new Vector2(1.5f),
|
||||||
},
|
},
|
||||||
counter = new LegacyRollingCounter(skin, LegacyFont.Combo)
|
counter = new LegacyRollingCounter(LegacyFont.Combo)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Mods
|
namespace osu.Game.Rulesets.Mania.Mods
|
||||||
@ -39,5 +40,13 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Edit.Checks;
|
using osu.Game.Rulesets.Osu.Edit.Checks;
|
||||||
@ -224,12 +225,14 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
|
|||||||
|
|
||||||
private void assertOk(IBeatmap beatmap)
|
private void assertOk(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
Assert.That(check.Run(beatmap, new TestWorkingBeatmap(beatmap)), Is.Empty);
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
Assert.That(check.Run(context), Is.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertOffscreenCircle(IBeatmap beatmap)
|
private void assertOffscreenCircle(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
var issues = check.Run(beatmap, new TestWorkingBeatmap(beatmap)).ToList();
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckOffscreenObjects.IssueTemplateOffscreenCircle);
|
Assert.That(issues.Single().Template is CheckOffscreenObjects.IssueTemplateOffscreenCircle);
|
||||||
@ -237,7 +240,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
|
|||||||
|
|
||||||
private void assertOffscreenSlider(IBeatmap beatmap)
|
private void assertOffscreenSlider(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
var issues = check.Run(beatmap, new TestWorkingBeatmap(beatmap)).ToList();
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckOffscreenObjects.IssueTemplateOffscreenSlider);
|
Assert.That(issues.Single().Template is CheckOffscreenObjects.IssueTemplateOffscreenSlider);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Checks.Components;
|
using osu.Game.Rulesets.Edit.Checks.Components;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -31,9 +31,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Checks
|
|||||||
new IssueTemplateOffscreenSlider(this)
|
new IssueTemplateOffscreenSlider(this)
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, IWorkingBeatmap workingBeatmap)
|
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||||
{
|
{
|
||||||
foreach (var hitobject in playableBeatmap.HitObjects)
|
foreach (var hitobject in context.Beatmap.HitObjects)
|
||||||
{
|
{
|
||||||
switch (hitobject)
|
switch (hitobject)
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Checks.Components;
|
using osu.Game.Rulesets.Edit.Checks.Components;
|
||||||
using osu.Game.Rulesets.Osu.Edit.Checks;
|
using osu.Game.Rulesets.Osu.Edit.Checks;
|
||||||
@ -17,9 +16,9 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
new CheckOffscreenObjects()
|
new CheckOffscreenObjects()
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, WorkingBeatmap workingBeatmap)
|
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||||
{
|
{
|
||||||
return checks.SelectMany(check => check.Run(playableBeatmap, workingBeatmap));
|
return checks.SelectMany(check => check.Run(context));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,12 +12,23 @@ using osu.Game.Rulesets.Objects;
|
|||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Screens.Edit.Compose.Components;
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
using osuTK;
|
using Vector2 = osuTK.Vector2;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Edit
|
namespace osu.Game.Rulesets.Osu.Edit
|
||||||
{
|
{
|
||||||
public class OsuSelectionHandler : EditorSelectionHandler
|
public class OsuSelectionHandler : EditorSelectionHandler
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// During a transform, the initial origin is stored so it can be used throughout the operation.
|
||||||
|
/// </summary>
|
||||||
|
private Vector2? referenceOrigin;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// During a transform, the initial path types of a single selected slider are stored so they
|
||||||
|
/// can be maintained throughout the operation.
|
||||||
|
/// </summary>
|
||||||
|
private List<PathType?> referencePathTypes;
|
||||||
|
|
||||||
protected override void OnSelectionChanged()
|
protected override void OnSelectionChanged()
|
||||||
{
|
{
|
||||||
base.OnSelectionChanged();
|
base.OnSelectionChanged();
|
||||||
@ -50,17 +61,6 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// During a transform, the initial origin is stored so it can be used throughout the operation.
|
|
||||||
/// </summary>
|
|
||||||
private Vector2? referenceOrigin;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// During a transform, the initial path types of a single selected slider are stored so they
|
|
||||||
/// can be maintained throughout the operation.
|
|
||||||
/// </summary>
|
|
||||||
private List<PathType?> referencePathTypes;
|
|
||||||
|
|
||||||
public override bool HandleReverse()
|
public override bool HandleReverse()
|
||||||
{
|
{
|
||||||
var hitObjects = EditorBeatmap.SelectedHitObjects;
|
var hitObjects = EditorBeatmap.SelectedHitObjects;
|
||||||
@ -114,24 +114,10 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
var hitObjects = selectedMovableObjects;
|
var hitObjects = selectedMovableObjects;
|
||||||
|
|
||||||
var selectedObjectsQuad = getSurroundingQuad(hitObjects);
|
var selectedObjectsQuad = getSurroundingQuad(hitObjects);
|
||||||
var centre = selectedObjectsQuad.Centre;
|
|
||||||
|
|
||||||
foreach (var h in hitObjects)
|
foreach (var h in hitObjects)
|
||||||
{
|
{
|
||||||
var pos = h.Position;
|
h.Position = GetFlippedPosition(direction, selectedObjectsQuad, h.Position);
|
||||||
|
|
||||||
switch (direction)
|
|
||||||
{
|
|
||||||
case Direction.Horizontal:
|
|
||||||
pos.X = centre.X - (pos.X - centre.X);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Direction.Vertical:
|
|
||||||
pos.Y = centre.Y - (pos.Y - centre.Y);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
h.Position = pos;
|
|
||||||
|
|
||||||
if (h is Slider slider)
|
if (h is Slider slider)
|
||||||
{
|
{
|
||||||
@ -204,7 +190,7 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
{
|
{
|
||||||
referencePathTypes ??= slider.Path.ControlPoints.Select(p => p.Type.Value).ToList();
|
referencePathTypes ??= slider.Path.ControlPoints.Select(p => p.Type.Value).ToList();
|
||||||
|
|
||||||
Quad sliderQuad = getSurroundingQuad(slider.Path.ControlPoints.Select(p => p.Position.Value));
|
Quad sliderQuad = GetSurroundingQuad(slider.Path.ControlPoints.Select(p => p.Position.Value));
|
||||||
|
|
||||||
// Limit minimum distance between control points after scaling to almost 0. Less than 0 causes the slider to flip, exactly 0 causes a crash through division by 0.
|
// Limit minimum distance between control points after scaling to almost 0. Less than 0 causes the slider to flip, exactly 0 causes a crash through division by 0.
|
||||||
scale = Vector2.ComponentMax(new Vector2(Precision.FLOAT_EPSILON), sliderQuad.Size + scale) - sliderQuad.Size;
|
scale = Vector2.ComponentMax(new Vector2(Precision.FLOAT_EPSILON), sliderQuad.Size + scale) - sliderQuad.Size;
|
||||||
@ -333,7 +319,7 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="hitObjects">The hit objects to calculate a quad for.</param>
|
/// <param name="hitObjects">The hit objects to calculate a quad for.</param>
|
||||||
private Quad getSurroundingQuad(OsuHitObject[] hitObjects) =>
|
private Quad getSurroundingQuad(OsuHitObject[] hitObjects) =>
|
||||||
getSurroundingQuad(hitObjects.SelectMany(h =>
|
GetSurroundingQuad(hitObjects.SelectMany(h =>
|
||||||
{
|
{
|
||||||
if (h is IHasPath path)
|
if (h is IHasPath path)
|
||||||
{
|
{
|
||||||
@ -348,30 +334,6 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
return new[] { h.Position };
|
return new[] { h.Position };
|
||||||
}));
|
}));
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a gamefield-space quad surrounding the provided points.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="points">The points to calculate a quad for.</param>
|
|
||||||
private Quad getSurroundingQuad(IEnumerable<Vector2> points)
|
|
||||||
{
|
|
||||||
if (!EditorBeatmap.SelectedHitObjects.Any())
|
|
||||||
return new Quad();
|
|
||||||
|
|
||||||
Vector2 minPosition = new Vector2(float.MaxValue, float.MaxValue);
|
|
||||||
Vector2 maxPosition = new Vector2(float.MinValue, float.MinValue);
|
|
||||||
|
|
||||||
// Go through all hitobjects to make sure they would remain in the bounds of the editor after movement, before any movement is attempted
|
|
||||||
foreach (var p in points)
|
|
||||||
{
|
|
||||||
minPosition = Vector2.ComponentMin(minPosition, p);
|
|
||||||
maxPosition = Vector2.ComponentMax(maxPosition, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector2 size = maxPosition - minPosition;
|
|
||||||
|
|
||||||
return new Quad(minPosition.X, minPosition.Y, size.X, size.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All osu! hitobjects which can be moved/rotated/scaled.
|
/// All osu! hitobjects which can be moved/rotated/scaled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -43,13 +43,11 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
|
|
||||||
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
||||||
{
|
{
|
||||||
base.ApplyIncreasedVisibilityState(hitObject, state);
|
|
||||||
applyState(hitObject, true);
|
applyState(hitObject, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
||||||
{
|
{
|
||||||
base.ApplyNormalVisibilityState(hitObject, state);
|
|
||||||
applyState(hitObject, false);
|
applyState(hitObject, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,20 +58,20 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
|
|
||||||
OsuHitObject hitObject = drawableOsuObject.HitObject;
|
OsuHitObject hitObject = drawableOsuObject.HitObject;
|
||||||
|
|
||||||
(double startTime, double duration) fadeOut = getFadeOutParameters(drawableOsuObject);
|
(double fadeStartTime, double fadeDuration) = getFadeOutParameters(drawableOsuObject);
|
||||||
|
|
||||||
switch (drawableObject)
|
switch (drawableObject)
|
||||||
{
|
{
|
||||||
case DrawableSliderTail _:
|
case DrawableSliderTail _:
|
||||||
using (drawableObject.BeginAbsoluteSequence(fadeOut.startTime, true))
|
using (drawableObject.BeginAbsoluteSequence(fadeStartTime))
|
||||||
drawableObject.FadeOut(fadeOut.duration);
|
drawableObject.FadeOut(fadeDuration);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DrawableSliderRepeat sliderRepeat:
|
case DrawableSliderRepeat sliderRepeat:
|
||||||
using (drawableObject.BeginAbsoluteSequence(fadeOut.startTime, true))
|
using (drawableObject.BeginAbsoluteSequence(fadeStartTime))
|
||||||
// only apply to circle piece – reverse arrow is not affected by hidden.
|
// only apply to circle piece – reverse arrow is not affected by hidden.
|
||||||
sliderRepeat.CirclePiece.FadeOut(fadeOut.duration);
|
sliderRepeat.CirclePiece.FadeOut(fadeDuration);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -88,23 +86,23 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// we don't want to see the approach circle
|
// we don't want to see the approach circle
|
||||||
using (circle.BeginAbsoluteSequence(hitObject.StartTime - hitObject.TimePreempt, true))
|
using (circle.BeginAbsoluteSequence(hitObject.StartTime - hitObject.TimePreempt))
|
||||||
circle.ApproachCircle.Hide();
|
circle.ApproachCircle.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
using (drawableObject.BeginAbsoluteSequence(fadeOut.startTime, true))
|
using (drawableObject.BeginAbsoluteSequence(fadeStartTime))
|
||||||
fadeTarget.FadeOut(fadeOut.duration);
|
fadeTarget.FadeOut(fadeDuration);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DrawableSlider slider:
|
case DrawableSlider slider:
|
||||||
using (slider.BeginAbsoluteSequence(fadeOut.startTime, true))
|
using (slider.BeginAbsoluteSequence(fadeStartTime))
|
||||||
slider.Body.FadeOut(fadeOut.duration, Easing.Out);
|
slider.Body.FadeOut(fadeDuration, Easing.Out);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DrawableSliderTick sliderTick:
|
case DrawableSliderTick sliderTick:
|
||||||
using (sliderTick.BeginAbsoluteSequence(fadeOut.startTime, true))
|
using (sliderTick.BeginAbsoluteSequence(fadeStartTime))
|
||||||
sliderTick.FadeOut(fadeOut.duration);
|
sliderTick.FadeOut(fadeDuration);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -112,14 +110,14 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
// hide elements we don't care about.
|
// hide elements we don't care about.
|
||||||
// todo: hide background
|
// todo: hide background
|
||||||
|
|
||||||
using (spinner.BeginAbsoluteSequence(fadeOut.startTime, true))
|
using (spinner.BeginAbsoluteSequence(fadeStartTime))
|
||||||
spinner.FadeOut(fadeOut.duration);
|
spinner.FadeOut(fadeDuration);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private (double startTime, double duration) getFadeOutParameters(DrawableOsuHitObject drawableObject)
|
private (double fadeStartTime, double fadeDuration) getFadeOutParameters(DrawableOsuHitObject drawableObject)
|
||||||
{
|
{
|
||||||
switch (drawableObject)
|
switch (drawableObject)
|
||||||
{
|
{
|
||||||
@ -137,7 +135,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
return getParameters(drawableObject.HitObject);
|
return getParameters(drawableObject.HitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
static (double startTime, double duration) getParameters(OsuHitObject hitObject)
|
static (double fadeStartTime, double fadeDuration) getParameters(OsuHitObject hitObject)
|
||||||
{
|
{
|
||||||
var fadeOutStartTime = hitObject.StartTime - hitObject.TimePreempt + hitObject.TimeFadeIn;
|
var fadeOutStartTime = hitObject.StartTime - hitObject.TimePreempt + hitObject.TimeFadeIn;
|
||||||
var fadeOutDuration = hitObject.TimePreempt * fade_out_duration_multiplier;
|
var fadeOutDuration = hitObject.TimePreempt * fade_out_duration_multiplier;
|
||||||
|
@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
Scale = new Vector2(SPRITE_SCALE),
|
Scale = new Vector2(SPRITE_SCALE),
|
||||||
Y = SPINNER_TOP_OFFSET + 115,
|
Y = SPINNER_TOP_OFFSET + 115,
|
||||||
},
|
},
|
||||||
bonusCounter = new LegacySpriteText(source, LegacyFont.Score)
|
bonusCounter = new LegacySpriteText(LegacyFont.Score)
|
||||||
{
|
{
|
||||||
Alpha = 0f,
|
Alpha = 0f,
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
Scale = new Vector2(SPRITE_SCALE),
|
Scale = new Vector2(SPRITE_SCALE),
|
||||||
Position = new Vector2(-87, 445 + spm_hide_offset),
|
Position = new Vector2(-87, 445 + spm_hide_offset),
|
||||||
},
|
},
|
||||||
spmCounter = new LegacySpriteText(source, LegacyFont.Score)
|
spmCounter = new LegacySpriteText(LegacyFont.Score)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
|
@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
if (!this.HasFont(LegacyFont.HitCircle))
|
if (!this.HasFont(LegacyFont.HitCircle))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return new LegacySpriteText(Source, LegacyFont.HitCircle)
|
return new LegacySpriteText(LegacyFont.HitCircle)
|
||||||
{
|
{
|
||||||
// stable applies a blanket 0.8x scale to hitcircle fonts
|
// stable applies a blanket 0.8x scale to hitcircle fonts
|
||||||
Scale = new Vector2(0.8f),
|
Scale = new Vector2(0.8f),
|
||||||
|
@ -166,7 +166,7 @@ namespace osu.Game.Rulesets.Osu.Statistics
|
|||||||
|
|
||||||
var point = new HitPoint(pointType, this)
|
var point = new HitPoint(pointType, this)
|
||||||
{
|
{
|
||||||
Colour = pointType == HitPointType.Hit ? new Color4(102, 255, 204, 255) : new Color4(255, 102, 102, 255)
|
BaseColour = pointType == HitPointType.Hit ? new Color4(102, 255, 204, 255) : new Color4(255, 102, 102, 255)
|
||||||
};
|
};
|
||||||
|
|
||||||
points[r][c] = point;
|
points[r][c] = point;
|
||||||
@ -234,6 +234,11 @@ namespace osu.Game.Rulesets.Osu.Statistics
|
|||||||
|
|
||||||
private class HitPoint : Circle
|
private class HitPoint : Circle
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The base colour which will be lightened/darkened depending on the value of this <see cref="HitPoint"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Color4 BaseColour;
|
||||||
|
|
||||||
private readonly HitPointType pointType;
|
private readonly HitPointType pointType;
|
||||||
private readonly AccuracyHeatmap heatmap;
|
private readonly AccuracyHeatmap heatmap;
|
||||||
|
|
||||||
@ -284,7 +289,7 @@ namespace osu.Game.Rulesets.Osu.Statistics
|
|||||||
|
|
||||||
Alpha = Math.Min(amount / lighten_cutoff, 1);
|
Alpha = Math.Min(amount / lighten_cutoff, 1);
|
||||||
if (pointType == HitPointType.Hit)
|
if (pointType == HitPointType.Hit)
|
||||||
Colour = ((Color4)Colour).Lighten(Math.Max(0, amount - lighten_cutoff));
|
Colour = BaseColour.Lighten(Math.Max(0, amount - lighten_cutoff));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
|
|
||||||
var hitWindows = new OsuHitWindows();
|
var hitWindows = new OsuHitWindows();
|
||||||
foreach (var result in Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => r > HitResult.None && hitWindows.IsHitResultAllowed(r)))
|
foreach (var result in Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => r > HitResult.None && hitWindows.IsHitResultAllowed(r)))
|
||||||
poolDictionary.Add(result, new DrawableJudgementPool(result, onJudgmentLoaded));
|
poolDictionary.Add(result, new DrawableJudgementPool(result, onJudgementLoaded));
|
||||||
|
|
||||||
AddRangeInternal(poolDictionary.Values);
|
AddRangeInternal(poolDictionary.Values);
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onJudgmentLoaded(DrawableOsuJudgement judgement)
|
private void onJudgementLoaded(DrawableOsuJudgement judgement)
|
||||||
{
|
{
|
||||||
judgementAboveHitObjectLayer.Add(judgement.GetProxyAboveHitObjectsContent());
|
judgementAboveHitObjectLayer.Add(judgement.GetProxyAboveHitObjectsContent());
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ using osu.Framework.Extensions.IEnumerableExtensions;
|
|||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.Skinning.Legacy;
|
using osu.Game.Rulesets.Taiko.Skinning.Legacy;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
@ -27,7 +28,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
AddToggleStep("Toggle passing", passing => this.ChildrenOfType<LegacyTaikoScroller>().ForEach(s => s.LastResult.Value =
|
AddToggleStep("Toggle passing", passing => this.ChildrenOfType<LegacyTaikoScroller>().ForEach(s => s.LastResult.Value =
|
||||||
new JudgementResult(null, new Judgement()) { Type = passing ? HitResult.Great : HitResult.Miss }));
|
new JudgementResult(new HitObject(), new Judgement()) { Type = passing ? HitResult.Great : HitResult.Miss }));
|
||||||
|
|
||||||
AddToggleStep("toggle playback direction", reversed => this.reversed = reversed);
|
AddToggleStep("toggle playback direction", reversed => this.reversed = reversed);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Mods
|
namespace osu.Game.Rulesets.Taiko.Mods
|
||||||
{
|
{
|
||||||
@ -10,5 +11,13 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
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 => 1.06;
|
||||||
public override bool HasImplementation => false;
|
public override bool HasImplementation => false;
|
||||||
|
|
||||||
|
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
@ -12,6 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
public class TaikoModRandom : ModRandom, IApplicableToBeatmap
|
public class TaikoModRandom : ModRandom, IApplicableToBeatmap
|
||||||
{
|
{
|
||||||
public override string Description => @"Shuffle around the colours!";
|
public override string Description => @"Shuffle around the colours!";
|
||||||
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(TaikoModSwap)).ToArray();
|
||||||
|
|
||||||
public void ApplyToBeatmap(IBeatmap beatmap)
|
public void ApplyToBeatmap(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
|
33
osu.Game.Rulesets.Taiko/Mods/TaikoModSwap.cs
Normal file
33
osu.Game.Rulesets.Taiko/Mods/TaikoModSwap.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Taiko.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Mods
|
||||||
|
{
|
||||||
|
public class TaikoModSwap : Mod, IApplicableToBeatmap
|
||||||
|
{
|
||||||
|
public override string Name => "Swap";
|
||||||
|
public override string Acronym => "SW";
|
||||||
|
public override string Description => @"Dons become kats, kats become dons";
|
||||||
|
public override ModType Type => ModType.Conversion;
|
||||||
|
public override double ScoreMultiplier => 1;
|
||||||
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModRandom)).ToArray();
|
||||||
|
|
||||||
|
public void ApplyToBeatmap(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
var taikoBeatmap = (TaikoBeatmap)beatmap;
|
||||||
|
|
||||||
|
foreach (var obj in taikoBeatmap.HitObjects)
|
||||||
|
{
|
||||||
|
if (obj is Hit hit)
|
||||||
|
hit.Type = hit.Type == HitType.Centre ? HitType.Rim : HitType.Centre;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
|
|||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
// store X before checking wide enough so if we perform layout there is no positional discrepancy.
|
// store X before checking wide enough so if we perform layout there is no positional discrepancy.
|
||||||
float currentX = (InternalChildren?.FirstOrDefault()?.X ?? 0) - (float)Clock.ElapsedFrameTime * 0.1f;
|
float currentX = (InternalChildren.FirstOrDefault()?.X ?? 0) - (float)Clock.ElapsedFrameTime * 0.1f;
|
||||||
|
|
||||||
// ensure we have enough sprites
|
// ensure we have enough sprites
|
||||||
if (!InternalChildren.Any()
|
if (!InternalChildren.Any()
|
||||||
|
@ -136,6 +136,7 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
new TaikoModRandom(),
|
new TaikoModRandom(),
|
||||||
new TaikoModDifficultyAdjust(),
|
new TaikoModDifficultyAdjust(),
|
||||||
new TaikoModClassic(),
|
new TaikoModClassic(),
|
||||||
|
new TaikoModSwap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
case ModType.Automation:
|
case ModType.Automation:
|
||||||
|
@ -12,6 +12,7 @@ using osu.Framework.Platform;
|
|||||||
using osu.Game.IPC;
|
using osu.Game.IPC;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
@ -264,7 +265,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
|
|
||||||
// change filename
|
// change filename
|
||||||
var firstFile = new FileInfo(Directory.GetFiles(extractedFolder).First());
|
var firstFile = new FileInfo(Directory.GetFiles(extractedFolder).First());
|
||||||
firstFile.MoveTo(Path.Combine(firstFile.DirectoryName, $"{firstFile.Name}-changed{firstFile.Extension}"));
|
firstFile.MoveTo(Path.Combine(firstFile.DirectoryName.AsNonNull(), $"{firstFile.Name}-changed{firstFile.Extension}"));
|
||||||
|
|
||||||
using (var zip = ZipArchive.Create())
|
using (var zip = ZipArchive.Create())
|
||||||
{
|
{
|
||||||
|
@ -6,6 +6,7 @@ using Moq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Checks;
|
using osu.Game.Rulesets.Edit.Checks;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
@ -40,23 +41,23 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
mock.SetupGet(w => w.Beatmap).Returns(beatmap);
|
mock.SetupGet(w => w.Beatmap).Returns(beatmap);
|
||||||
mock.SetupGet(w => w.Track).Returns((Track)null);
|
mock.SetupGet(w => w.Track).Returns((Track)null);
|
||||||
|
|
||||||
Assert.That(check.Run(beatmap, mock.Object), Is.Empty);
|
Assert.That(check.Run(new BeatmapVerifierContext(beatmap, mock.Object)), Is.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestAcceptable()
|
public void TestAcceptable()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(192);
|
var context = getContext(192);
|
||||||
|
|
||||||
Assert.That(check.Run(beatmap, mock.Object), Is.Empty);
|
Assert.That(check.Run(context), Is.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestNullBitrate()
|
public void TestNullBitrate()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(null);
|
var context = getContext(null);
|
||||||
|
|
||||||
var issues = check.Run(beatmap, mock.Object).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateNoBitrate);
|
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateNoBitrate);
|
||||||
@ -65,9 +66,9 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestZeroBitrate()
|
public void TestZeroBitrate()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(0);
|
var context = getContext(0);
|
||||||
|
|
||||||
var issues = check.Run(beatmap, mock.Object).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateNoBitrate);
|
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateNoBitrate);
|
||||||
@ -76,9 +77,9 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestTooHighBitrate()
|
public void TestTooHighBitrate()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(320);
|
var context = getContext(320);
|
||||||
|
|
||||||
var issues = check.Run(beatmap, mock.Object).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateTooHighBitrate);
|
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateTooHighBitrate);
|
||||||
@ -87,14 +88,19 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestTooLowBitrate()
|
public void TestTooLowBitrate()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(64);
|
var context = getContext(64);
|
||||||
|
|
||||||
var issues = check.Run(beatmap, mock.Object).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateTooLowBitrate);
|
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateTooLowBitrate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BeatmapVerifierContext getContext(int? audioBitrate)
|
||||||
|
{
|
||||||
|
return new BeatmapVerifierContext(beatmap, getMockWorkingBeatmap(audioBitrate).Object);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the mock of the working beatmap with the given audio properties.
|
/// Returns the mock of the working beatmap with the given audio properties.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -9,6 +9,7 @@ using Moq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Checks;
|
using osu.Game.Rulesets.Edit.Checks;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using FileInfo = osu.Game.IO.FileInfo;
|
using FileInfo = osu.Game.IO.FileInfo;
|
||||||
@ -53,25 +54,25 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
{
|
{
|
||||||
// While this is a problem, it is out of scope for this check and is caught by a different one.
|
// While this is a problem, it is out of scope for this check and is caught by a different one.
|
||||||
beatmap.Metadata.BackgroundFile = null;
|
beatmap.Metadata.BackgroundFile = null;
|
||||||
var mock = getMockWorkingBeatmap(null, System.Array.Empty<byte>());
|
var context = getContext(null, System.Array.Empty<byte>());
|
||||||
|
|
||||||
Assert.That(check.Run(beatmap, mock.Object), Is.Empty);
|
Assert.That(check.Run(context), Is.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestAcceptable()
|
public void TestAcceptable()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(new Texture(1920, 1080));
|
var context = getContext(new Texture(1920, 1080));
|
||||||
|
|
||||||
Assert.That(check.Run(beatmap, mock.Object), Is.Empty);
|
Assert.That(check.Run(context), Is.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestTooHighResolution()
|
public void TestTooHighResolution()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(new Texture(3840, 2160));
|
var context = getContext(new Texture(3840, 2160));
|
||||||
|
|
||||||
var issues = check.Run(beatmap, mock.Object).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateTooHighResolution);
|
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateTooHighResolution);
|
||||||
@ -80,9 +81,9 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestLowResolution()
|
public void TestLowResolution()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(new Texture(640, 480));
|
var context = getContext(new Texture(640, 480));
|
||||||
|
|
||||||
var issues = check.Run(beatmap, mock.Object).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateLowResolution);
|
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateLowResolution);
|
||||||
@ -91,9 +92,9 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestTooLowResolution()
|
public void TestTooLowResolution()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(new Texture(100, 100));
|
var context = getContext(new Texture(100, 100));
|
||||||
|
|
||||||
var issues = check.Run(beatmap, mock.Object).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateTooLowResolution);
|
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateTooLowResolution);
|
||||||
@ -102,14 +103,19 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestTooUncompressed()
|
public void TestTooUncompressed()
|
||||||
{
|
{
|
||||||
var mock = getMockWorkingBeatmap(new Texture(1920, 1080), new byte[1024 * 1024 * 3]);
|
var context = getContext(new Texture(1920, 1080), new byte[1024 * 1024 * 3]);
|
||||||
|
|
||||||
var issues = check.Run(beatmap, mock.Object).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateTooUncompressed);
|
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateTooUncompressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BeatmapVerifierContext getContext(Texture background, [CanBeNull] byte[] fileBytes = null)
|
||||||
|
{
|
||||||
|
return new BeatmapVerifierContext(beatmap, getMockWorkingBeatmap(background, fileBytes).Object);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the mock of the working beatmap with the given background and filesize.
|
/// Returns the mock of the working beatmap with the given background and filesize.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -6,11 +6,13 @@ using System.Linq;
|
|||||||
using Moq;
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Checks;
|
using osu.Game.Rulesets.Edit.Checks;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Tests.Beatmaps;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Editing.Checks
|
namespace osu.Game.Tests.Editing.Checks
|
||||||
{
|
{
|
||||||
@ -105,7 +107,7 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
new HitCircle { StartTime = 300 }
|
new HitCircle { StartTime = 300 }
|
||||||
};
|
};
|
||||||
|
|
||||||
var issues = check.Run(getPlayableBeatmap(hitobjects), null).ToList();
|
var issues = check.Run(getContext(hitobjects)).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(3));
|
Assert.That(issues, Has.Count.EqualTo(3));
|
||||||
Assert.That(issues.Where(issue => issue.Template is CheckConcurrentObjects.IssueTemplateConcurrentDifferent).ToList(), Has.Count.EqualTo(2));
|
Assert.That(issues.Where(issue => issue.Template is CheckConcurrentObjects.IssueTemplateConcurrentDifferent).ToList(), Has.Count.EqualTo(2));
|
||||||
@ -164,12 +166,12 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
|
|
||||||
private void assertOk(List<HitObject> hitobjects)
|
private void assertOk(List<HitObject> hitobjects)
|
||||||
{
|
{
|
||||||
Assert.That(check.Run(getPlayableBeatmap(hitobjects), null), Is.Empty);
|
Assert.That(check.Run(getContext(hitobjects)), Is.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertConcurrentSame(List<HitObject> hitobjects, int count = 1)
|
private void assertConcurrentSame(List<HitObject> hitobjects, int count = 1)
|
||||||
{
|
{
|
||||||
var issues = check.Run(getPlayableBeatmap(hitobjects), null).ToList();
|
var issues = check.Run(getContext(hitobjects)).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(count));
|
Assert.That(issues, Has.Count.EqualTo(count));
|
||||||
Assert.That(issues.All(issue => issue.Template is CheckConcurrentObjects.IssueTemplateConcurrentSame));
|
Assert.That(issues.All(issue => issue.Template is CheckConcurrentObjects.IssueTemplateConcurrentSame));
|
||||||
@ -177,18 +179,16 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
|
|
||||||
private void assertConcurrentDifferent(List<HitObject> hitobjects, int count = 1)
|
private void assertConcurrentDifferent(List<HitObject> hitobjects, int count = 1)
|
||||||
{
|
{
|
||||||
var issues = check.Run(getPlayableBeatmap(hitobjects), null).ToList();
|
var issues = check.Run(getContext(hitobjects)).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(count));
|
Assert.That(issues, Has.Count.EqualTo(count));
|
||||||
Assert.That(issues.All(issue => issue.Template is CheckConcurrentObjects.IssueTemplateConcurrentDifferent));
|
Assert.That(issues.All(issue => issue.Template is CheckConcurrentObjects.IssueTemplateConcurrentDifferent));
|
||||||
}
|
}
|
||||||
|
|
||||||
private IBeatmap getPlayableBeatmap(List<HitObject> hitobjects)
|
private BeatmapVerifierContext getContext(List<HitObject> hitobjects)
|
||||||
{
|
{
|
||||||
return new Beatmap<HitObject>
|
var beatmap = new Beatmap<HitObject> { HitObjects = hitobjects };
|
||||||
{
|
return new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
HitObjects = hitobjects
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Checks;
|
using osu.Game.Rulesets.Edit.Checks;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Tests.Beatmaps;
|
using osu.Game.Tests.Beatmaps;
|
||||||
@ -45,7 +46,8 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestBackgroundSetAndInFiles()
|
public void TestBackgroundSetAndInFiles()
|
||||||
{
|
{
|
||||||
Assert.That(check.Run(beatmap, new TestWorkingBeatmap(beatmap)), Is.Empty);
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
Assert.That(check.Run(context), Is.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -53,7 +55,8 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
{
|
{
|
||||||
beatmap.BeatmapInfo.BeatmapSet.Files.Clear();
|
beatmap.BeatmapInfo.BeatmapSet.Files.Clear();
|
||||||
|
|
||||||
var issues = check.Run(beatmap, new TestWorkingBeatmap(beatmap)).ToList();
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckFilePresence.IssueTemplateDoesNotExist);
|
Assert.That(issues.Single().Template is CheckFilePresence.IssueTemplateDoesNotExist);
|
||||||
@ -64,7 +67,8 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
{
|
{
|
||||||
beatmap.Metadata.BackgroundFile = null;
|
beatmap.Metadata.BackgroundFile = null;
|
||||||
|
|
||||||
var issues = check.Run(beatmap, new TestWorkingBeatmap(beatmap)).ToList();
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckFilePresence.IssueTemplateNoneSet);
|
Assert.That(issues.Single().Template is CheckFilePresence.IssueTemplateNoneSet);
|
||||||
|
@ -7,10 +7,12 @@ using Moq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Checks;
|
using osu.Game.Rulesets.Edit.Checks;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Tests.Beatmaps;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Editing.Checks
|
namespace osu.Game.Tests.Editing.Checks
|
||||||
{
|
{
|
||||||
@ -100,12 +102,12 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
}, count: 2);
|
}, count: 2);
|
||||||
|
|
||||||
// Start and end are 2 ms and 1.25 ms off respectively, hence two different issues in one object.
|
// Start and end are 2 ms and 1.25 ms off respectively, hence two different issues in one object.
|
||||||
var hitobjects = new List<HitObject>
|
var hitObjects = new List<HitObject>
|
||||||
{
|
{
|
||||||
getSliderMock(startTime: 98, endTime: 398.75d).Object
|
getSliderMock(startTime: 98, endTime: 398.75d).Object
|
||||||
};
|
};
|
||||||
|
|
||||||
var issues = check.Run(getPlayableBeatmap(hitobjects), null).ToList();
|
var issues = check.Run(getContext(hitObjects)).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(2));
|
Assert.That(issues, Has.Count.EqualTo(2));
|
||||||
Assert.That(issues.Any(issue => issue.Template is CheckUnsnappedObjects.IssueTemplateSmallUnsnap));
|
Assert.That(issues.Any(issue => issue.Template is CheckUnsnappedObjects.IssueTemplateSmallUnsnap));
|
||||||
@ -122,34 +124,36 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
return mockSlider;
|
return mockSlider;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertOk(List<HitObject> hitobjects)
|
private void assertOk(List<HitObject> hitObjects)
|
||||||
{
|
{
|
||||||
Assert.That(check.Run(getPlayableBeatmap(hitobjects), null), Is.Empty);
|
Assert.That(check.Run(getContext(hitObjects)), Is.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assert1Ms(List<HitObject> hitobjects, int count = 1)
|
private void assert1Ms(List<HitObject> hitObjects, int count = 1)
|
||||||
{
|
{
|
||||||
var issues = check.Run(getPlayableBeatmap(hitobjects), null).ToList();
|
var issues = check.Run(getContext(hitObjects)).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(count));
|
Assert.That(issues, Has.Count.EqualTo(count));
|
||||||
Assert.That(issues.All(issue => issue.Template is CheckUnsnappedObjects.IssueTemplateSmallUnsnap));
|
Assert.That(issues.All(issue => issue.Template is CheckUnsnappedObjects.IssueTemplateSmallUnsnap));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assert2Ms(List<HitObject> hitobjects, int count = 1)
|
private void assert2Ms(List<HitObject> hitObjects, int count = 1)
|
||||||
{
|
{
|
||||||
var issues = check.Run(getPlayableBeatmap(hitobjects), null).ToList();
|
var issues = check.Run(getContext(hitObjects)).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(count));
|
Assert.That(issues, Has.Count.EqualTo(count));
|
||||||
Assert.That(issues.All(issue => issue.Template is CheckUnsnappedObjects.IssueTemplateLargeUnsnap));
|
Assert.That(issues.All(issue => issue.Template is CheckUnsnappedObjects.IssueTemplateLargeUnsnap));
|
||||||
}
|
}
|
||||||
|
|
||||||
private IBeatmap getPlayableBeatmap(List<HitObject> hitobjects)
|
private BeatmapVerifierContext getContext(List<HitObject> hitObjects)
|
||||||
{
|
{
|
||||||
return new Beatmap<HitObject>
|
var beatmap = new Beatmap<HitObject>
|
||||||
{
|
{
|
||||||
ControlPointInfo = cpi,
|
ControlPointInfo = cpi,
|
||||||
HitObjects = hitobjects
|
HitObjects = hitObjects
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
173
osu.Game.Tests/Editing/TestSceneHitObjectContainerEventBuffer.cs
Normal file
173
osu.Game.Tests/Editing/TestSceneHitObjectContainerEventBuffer.cs
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
// 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 NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osu.Game.Screens.Edit.Compose;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Editing
|
||||||
|
{
|
||||||
|
public class TestSceneHitObjectContainerEventBuffer : OsuTestScene
|
||||||
|
{
|
||||||
|
private readonly TestHitObject testObj = new TestHitObject();
|
||||||
|
|
||||||
|
private TestPlayfield playfield1;
|
||||||
|
private TestPlayfield playfield2;
|
||||||
|
private TestDrawable intermediateDrawable;
|
||||||
|
private HitObjectUsageEventBuffer eventBuffer;
|
||||||
|
|
||||||
|
private HitObject beganUsage;
|
||||||
|
private HitObject finishedUsage;
|
||||||
|
private HitObject transferredUsage;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup() => Schedule(() =>
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
|
||||||
|
if (eventBuffer != null)
|
||||||
|
{
|
||||||
|
eventBuffer.HitObjectUsageBegan -= onHitObjectUsageBegan;
|
||||||
|
eventBuffer.HitObjectUsageFinished -= onHitObjectUsageFinished;
|
||||||
|
eventBuffer.HitObjectUsageTransferred -= onHitObjectUsageTransferred;
|
||||||
|
}
|
||||||
|
|
||||||
|
var topPlayfield = new TestPlayfield();
|
||||||
|
topPlayfield.AddNested(playfield1 = new TestPlayfield());
|
||||||
|
topPlayfield.AddNested(playfield2 = new TestPlayfield());
|
||||||
|
|
||||||
|
eventBuffer = new HitObjectUsageEventBuffer(topPlayfield);
|
||||||
|
eventBuffer.HitObjectUsageBegan += onHitObjectUsageBegan;
|
||||||
|
eventBuffer.HitObjectUsageFinished += onHitObjectUsageFinished;
|
||||||
|
eventBuffer.HitObjectUsageTransferred += onHitObjectUsageTransferred;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
topPlayfield,
|
||||||
|
intermediateDrawable = new TestDrawable(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
private void onHitObjectUsageBegan(HitObject obj) => beganUsage = obj;
|
||||||
|
|
||||||
|
private void onHitObjectUsageFinished(HitObject obj) => finishedUsage = obj;
|
||||||
|
|
||||||
|
private void onHitObjectUsageTransferred(HitObject obj, DrawableHitObject drawableObj) => transferredUsage = obj;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestUsageBeganAfterAdd()
|
||||||
|
{
|
||||||
|
AddStep("add hitobject", () => playfield1.Add(testObj));
|
||||||
|
addCheckStep(began: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestUsageFinishedAfterRemove()
|
||||||
|
{
|
||||||
|
AddStep("add hitobject", () => playfield1.Add(testObj));
|
||||||
|
addResetStep();
|
||||||
|
AddStep("remove hitobject", () => playfield1.Remove(testObj));
|
||||||
|
addCheckStep(finished: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestUsageTransferredWhenMovedBetweenPlayfields()
|
||||||
|
{
|
||||||
|
AddStep("add hitobject", () => playfield1.Add(testObj));
|
||||||
|
addResetStep();
|
||||||
|
AddStep("transfer hitobject to other playfield", () =>
|
||||||
|
{
|
||||||
|
playfield1.Remove(testObj);
|
||||||
|
playfield2.Add(testObj);
|
||||||
|
});
|
||||||
|
|
||||||
|
addCheckStep(transferred: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestRemoveImmediatelyAfterUsageBegan()
|
||||||
|
{
|
||||||
|
AddStep("add hitobject and schedule removal", () =>
|
||||||
|
{
|
||||||
|
playfield1.Add(testObj);
|
||||||
|
intermediateDrawable.Schedule(() => playfield1.Remove(testObj));
|
||||||
|
});
|
||||||
|
|
||||||
|
addCheckStep(began: true, finished: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestRemoveImmediatelyAfterTransferred()
|
||||||
|
{
|
||||||
|
AddStep("add hitobject", () => playfield1.Add(testObj));
|
||||||
|
addResetStep();
|
||||||
|
AddStep("transfer hitobject to other playfield and schedule removal", () =>
|
||||||
|
{
|
||||||
|
playfield1.Remove(testObj);
|
||||||
|
playfield2.Add(testObj);
|
||||||
|
intermediateDrawable.Schedule(() => playfield2.Remove(testObj));
|
||||||
|
});
|
||||||
|
|
||||||
|
addCheckStep(transferred: true, finished: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateAfterChildren()
|
||||||
|
{
|
||||||
|
base.UpdateAfterChildren();
|
||||||
|
eventBuffer.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addResetStep() => AddStep("reset", reset);
|
||||||
|
|
||||||
|
private void reset()
|
||||||
|
{
|
||||||
|
beganUsage = null;
|
||||||
|
finishedUsage = null;
|
||||||
|
transferredUsage = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addCheckStep(bool began = false, bool finished = false, bool transferred = false)
|
||||||
|
=> AddAssert($"began = {began}, finished = {finished}, transferred = {transferred}",
|
||||||
|
() => (beganUsage == testObj) == began && (finishedUsage == testObj) == finished && (transferredUsage == testObj) == transferred);
|
||||||
|
|
||||||
|
private class TestPlayfield : Playfield
|
||||||
|
{
|
||||||
|
public TestPlayfield()
|
||||||
|
{
|
||||||
|
RegisterPool<TestHitObject, TestDrawableHitObject>(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void AddNested(Playfield playfield)
|
||||||
|
{
|
||||||
|
AddInternal(playfield);
|
||||||
|
base.AddNested(playfield);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override HitObjectLifetimeEntry CreateLifetimeEntry(HitObject hitObject)
|
||||||
|
{
|
||||||
|
var entry = base.CreateLifetimeEntry(hitObject);
|
||||||
|
entry.KeepAlive = true;
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestHitObject : HitObject
|
||||||
|
{
|
||||||
|
public override string ToString() => "TestHitObject";
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestDrawableHitObject : DrawableHitObject
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestDrawable : Drawable
|
||||||
|
{
|
||||||
|
public new void Schedule(Action action) => base.Schedule(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -146,7 +146,7 @@ namespace osu.Game.Tests.Mods
|
|||||||
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
|
public abstract class CustomMod1 : Mod
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Humanizer;
|
using Humanizer;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Online.Multiplayer;
|
using osu.Game.Online.Multiplayer;
|
||||||
using osu.Game.Tests.Visual.Multiplayer;
|
using osu.Game.Tests.Visual.Multiplayer;
|
||||||
@ -34,7 +35,7 @@ namespace osu.Game.Tests.NonVisual.Multiplayer
|
|||||||
changeState(6, MultiplayerUserState.WaitingForLoad);
|
changeState(6, MultiplayerUserState.WaitingForLoad);
|
||||||
checkPlayingUserCount(6);
|
checkPlayingUserCount(6);
|
||||||
|
|
||||||
AddStep("another user left", () => Client.RemoveUser(Client.Room?.Users.Last().User));
|
AddStep("another user left", () => Client.RemoveUser((Client.Room?.Users.Last().User).AsNonNull()));
|
||||||
checkPlayingUserCount(5);
|
checkPlayingUserCount(5);
|
||||||
|
|
||||||
AddStep("leave room", () => Client.LeaveRoom());
|
AddStep("leave room", () => Client.LeaveRoom());
|
||||||
|
@ -167,5 +167,21 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
AddStep("move mouse away", () => InputManager.MoveMouseTo(selectionBox, new Vector2(20)));
|
AddStep("move mouse away", () => InputManager.MoveMouseTo(selectionBox, new Vector2(20)));
|
||||||
AddUntilStep("rotation handle hidden", () => rotationHandle.Alpha == 0);
|
AddUntilStep("rotation handle hidden", () => rotationHandle.Alpha == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tests that hovering over two handles instantaneously from one to another does not crash or cause issues to the visibility state.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestHoverOverTwoHandlesInstantaneously()
|
||||||
|
{
|
||||||
|
AddStep("hover over top-left scale handle", () =>
|
||||||
|
InputManager.MoveMouseTo(this.ChildrenOfType<SelectionBoxScaleHandle>().Single(s => s.Anchor == Anchor.TopLeft)));
|
||||||
|
AddStep("hover over top-right scale handle", () =>
|
||||||
|
InputManager.MoveMouseTo(this.ChildrenOfType<SelectionBoxScaleHandle>().Single(s => s.Anchor == Anchor.TopRight)));
|
||||||
|
AddUntilStep("top-left rotation handle hidden", () =>
|
||||||
|
this.ChildrenOfType<SelectionBoxRotationHandle>().Single(r => r.Anchor == Anchor.TopLeft).Alpha == 0);
|
||||||
|
AddUntilStep("top-right rotation handle shown", () =>
|
||||||
|
this.ChildrenOfType<SelectionBoxRotationHandle>().Single(r => r.Anchor == Anchor.TopRight).Alpha == 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
private void seekToBreak(int breakIndex)
|
private void seekToBreak(int breakIndex)
|
||||||
{
|
{
|
||||||
AddStep($"seek to break {breakIndex}", () => Player.GameplayClockContainer.Seek(destBreak().StartTime));
|
AddStep($"seek to break {breakIndex}", () => Player.GameplayClockContainer.Seek(destBreak().StartTime));
|
||||||
AddUntilStep("wait for seek to complete", () => Player.HUDOverlay.Progress.ReferenceClock.CurrentTime >= destBreak().StartTime);
|
AddUntilStep("wait for seek to complete", () => Player.DrawableRuleset.FrameStableClock.CurrentTime >= destBreak().StartTime);
|
||||||
|
|
||||||
BreakPeriod destBreak() => Beatmap.Value.Beatmap.Breaks.ElementAt(breakIndex);
|
BreakPeriod destBreak() => Beatmap.Value.Beatmap.Breaks.ElementAt(breakIndex);
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,18 @@
|
|||||||
// 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.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Gameplay
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
{
|
{
|
||||||
public class TestSceneComboCounter : SkinnableTestScene
|
public class TestSceneComboCounter : SkinnableTestScene
|
||||||
{
|
{
|
||||||
private IEnumerable<SkinnableComboCounter> comboCounters => CreatedDrawables.OfType<SkinnableComboCounter>();
|
|
||||||
|
|
||||||
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
|
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
@ -25,7 +21,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
public void SetUpSteps()
|
public void SetUpSteps()
|
||||||
{
|
{
|
||||||
AddStep("Create combo counters", () => SetContents(() => new SkinnableComboCounter()));
|
AddStep("Create combo counters", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.ComboCounter))));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -2,10 +2,12 @@
|
|||||||
// 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 NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Skinning;
|
||||||
using osu.Game.Skinning.Editor;
|
using osu.Game.Skinning.Editor;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Gameplay
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
@ -14,12 +16,17 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
private SkinEditor skinEditor;
|
private SkinEditor skinEditor;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private SkinManager skinManager { get; set; }
|
||||||
|
|
||||||
|
protected override bool Autoplay => true;
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
public override void SetUpSteps()
|
public override void SetUpSteps()
|
||||||
{
|
{
|
||||||
base.SetUpSteps();
|
base.SetUpSteps();
|
||||||
|
|
||||||
AddStep("add editor overlay", () =>
|
AddStep("reload skin editor", () =>
|
||||||
{
|
{
|
||||||
skinEditor?.Expire();
|
skinEditor?.Expire();
|
||||||
Player.ScaleTo(SkinEditorOverlay.VISIBLE_TARGET_SCALE);
|
Player.ScaleTo(SkinEditorOverlay.VISIBLE_TARGET_SCALE);
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
@ -32,12 +30,13 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
SetContents(() =>
|
SetContents(() =>
|
||||||
{
|
{
|
||||||
var ruleset = new OsuRuleset();
|
var ruleset = new OsuRuleset();
|
||||||
|
var mods = new[] { ruleset.GetAutoplayMod() };
|
||||||
var working = CreateWorkingBeatmap(ruleset.RulesetInfo);
|
var working = CreateWorkingBeatmap(ruleset.RulesetInfo);
|
||||||
var beatmap = working.GetPlayableBeatmap(ruleset.RulesetInfo);
|
var beatmap = working.GetPlayableBeatmap(ruleset.RulesetInfo, mods);
|
||||||
|
|
||||||
var drawableRuleset = ruleset.CreateDrawableRulesetWith(beatmap);
|
var drawableRuleset = ruleset.CreateDrawableRulesetWith(beatmap, mods);
|
||||||
|
|
||||||
var hudOverlay = new HUDOverlay(drawableRuleset, Array.Empty<Mod>())
|
var hudOverlay = new HUDOverlay(drawableRuleset, mods)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
@ -7,7 +7,7 @@ using osu.Framework.Testing;
|
|||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Gameplay
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
{
|
{
|
||||||
@ -22,7 +22,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
public void SetUpSteps()
|
public void SetUpSteps()
|
||||||
{
|
{
|
||||||
AddStep("Set initial accuracy", () => scoreProcessor.Accuracy.Value = 1);
|
AddStep("Set initial accuracy", () => scoreProcessor.Accuracy.Value = 1);
|
||||||
AddStep("Create accuracy counters", () => SetContents(() => new SkinnableAccuracyCounter()));
|
AddStep("Create accuracy counters", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.AccuracyCounter))));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -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.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
@ -12,14 +10,12 @@ using osu.Game.Rulesets.Osu;
|
|||||||
using osu.Game.Rulesets.Osu.Judgements;
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Gameplay
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
{
|
{
|
||||||
public class TestSceneSkinnableHealthDisplay : SkinnableTestScene
|
public class TestSceneSkinnableHealthDisplay : SkinnableTestScene
|
||||||
{
|
{
|
||||||
private IEnumerable<SkinnableHealthDisplay> healthDisplays => CreatedDrawables.OfType<SkinnableHealthDisplay>();
|
|
||||||
|
|
||||||
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
|
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
|
||||||
|
|
||||||
[Cached(typeof(HealthProcessor))]
|
[Cached(typeof(HealthProcessor))]
|
||||||
@ -28,10 +24,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
public void SetUpSteps()
|
public void SetUpSteps()
|
||||||
{
|
{
|
||||||
AddStep("Create health displays", () =>
|
AddStep("Create health displays", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.HealthDisplay))));
|
||||||
{
|
|
||||||
SetContents(() => new SkinnableHealthDisplay());
|
|
||||||
});
|
|
||||||
AddStep(@"Reset all", delegate
|
AddStep(@"Reset all", delegate
|
||||||
{
|
{
|
||||||
healthProcessor.Health.Value = 1;
|
healthProcessor.Health.Value = 1;
|
||||||
|
@ -1,23 +1,18 @@
|
|||||||
// 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.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Gameplay
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
{
|
{
|
||||||
public class TestSceneSkinnableScoreCounter : SkinnableTestScene
|
public class TestSceneSkinnableScoreCounter : SkinnableTestScene
|
||||||
{
|
{
|
||||||
private IEnumerable<SkinnableScoreCounter> scoreCounters => CreatedDrawables.OfType<SkinnableScoreCounter>();
|
|
||||||
|
|
||||||
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
|
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
@ -26,7 +21,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
public void SetUpSteps()
|
public void SetUpSteps()
|
||||||
{
|
{
|
||||||
AddStep("Create score counters", () => SetContents(() => new SkinnableScoreCounter()));
|
AddStep("Create score counters", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.ScoreCounter))));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -40,7 +35,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestVeryLargeScore()
|
public void TestVeryLargeScore()
|
||||||
{
|
{
|
||||||
AddStep("set large score", () => scoreCounters.ForEach(counter => scoreProcessor.TotalScore.Value = 1_000_000_000));
|
AddStep("set large score", () => scoreProcessor.TotalScore.Value = 1_000_000_000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
@ -45,14 +46,14 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
switch (args.Action)
|
switch (args.Action)
|
||||||
{
|
{
|
||||||
case NotifyCollectionChangedAction.Add:
|
case NotifyCollectionChangedAction.Add:
|
||||||
args.NewItems.Cast<Mod>().ForEach(mod => selectedMods.Add(new OsuSpriteText
|
args.NewItems.AsNonNull().Cast<Mod>().ForEach(mod => selectedMods.Add(new OsuSpriteText
|
||||||
{
|
{
|
||||||
Text = mod.Acronym,
|
Text = mod.Acronym,
|
||||||
}));
|
}));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NotifyCollectionChangedAction.Remove:
|
case NotifyCollectionChangedAction.Remove:
|
||||||
args.OldItems.Cast<Mod>().ForEach(mod =>
|
args.OldItems.AsNonNull().Cast<Mod>().ForEach(mod =>
|
||||||
{
|
{
|
||||||
foreach (var selected in selectedMods)
|
foreach (var selected in selectedMods)
|
||||||
{
|
{
|
||||||
|
@ -11,11 +11,13 @@ using osu.Framework.Platform;
|
|||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Screens.OnlinePlay;
|
using osu.Game.Screens.OnlinePlay;
|
||||||
using osu.Game.Screens.OnlinePlay.Playlists;
|
using osu.Game.Screens.OnlinePlay.Playlists;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Tests.Beatmaps;
|
using osu.Game.Tests.Beatmaps;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
@ -24,8 +26,6 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
{
|
{
|
||||||
public class TestScenePlaylistsRoomSubScreen : RoomTestScene
|
public class TestScenePlaylistsRoomSubScreen : RoomTestScene
|
||||||
{
|
{
|
||||||
protected override bool UseOnlineAPI => true;
|
|
||||||
|
|
||||||
[Cached(typeof(IRoomManager))]
|
[Cached(typeof(IRoomManager))]
|
||||||
private readonly TestRoomManager roomManager = new TestRoomManager();
|
private readonly TestRoomManager roomManager = new TestRoomManager();
|
||||||
|
|
||||||
@ -41,6 +41,18 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default));
|
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default));
|
||||||
|
|
||||||
manager.Import(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).Wait();
|
manager.Import(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).Wait();
|
||||||
|
|
||||||
|
((DummyAPIAccess)API).HandleRequest = req =>
|
||||||
|
{
|
||||||
|
switch (req)
|
||||||
|
{
|
||||||
|
case CreateRoomScoreRequest createRoomScoreRequest:
|
||||||
|
createRoomScoreRequest.TriggerSuccess(new APIScoreToken { ID = 1 });
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
@ -59,12 +71,16 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
Room.Name.Value = "my awesome room";
|
Room.Name.Value = "my awesome room";
|
||||||
Room.Host.Value = new User { Id = 2, Username = "peppy" };
|
Room.Host.Value = new User { Id = 2, Username = "peppy" };
|
||||||
Room.RecentParticipants.Add(Room.Host.Value);
|
Room.RecentParticipants.Add(Room.Host.Value);
|
||||||
|
Room.EndDate.Value = DateTimeOffset.Now.AddMinutes(5);
|
||||||
Room.Playlist.Add(new PlaylistItem
|
Room.Playlist.Add(new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
|
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo }
|
Ruleset = { Value = new OsuRuleset().RulesetInfo }
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AddStep("start match", () => match.ChildrenOfType<PlaylistsReadyButton>().First().Click());
|
||||||
|
AddUntilStep("player loader loaded", () => Stack.CurrentScreen is PlayerLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -1,32 +1,65 @@
|
|||||||
// 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.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Screens.Ranking.Expanded;
|
using osu.Game.Screens.Ranking.Expanded;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Ranking
|
namespace osu.Game.Tests.Visual.Ranking
|
||||||
{
|
{
|
||||||
public class TestSceneStarRatingDisplay : OsuTestScene
|
public class TestSceneStarRatingDisplay : OsuTestScene
|
||||||
{
|
{
|
||||||
public TestSceneStarRatingDisplay()
|
[Test]
|
||||||
|
public void TestDisplay()
|
||||||
{
|
{
|
||||||
Child = new FillFlowContainer
|
AddStep("load displays", () => Child = new FillFlowContainer
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Children = new Drawable[]
|
ChildrenEnumerable = new[]
|
||||||
{
|
{
|
||||||
new StarRatingDisplay(new StarDifficulty(1.23, 0)),
|
1.23,
|
||||||
new StarRatingDisplay(new StarDifficulty(2.34, 0)),
|
2.34,
|
||||||
new StarRatingDisplay(new StarDifficulty(3.45, 0)),
|
3.45,
|
||||||
new StarRatingDisplay(new StarDifficulty(4.56, 0)),
|
4.56,
|
||||||
new StarRatingDisplay(new StarDifficulty(5.67, 0)),
|
5.67,
|
||||||
new StarRatingDisplay(new StarDifficulty(6.78, 0)),
|
6.78,
|
||||||
new StarRatingDisplay(new StarDifficulty(10.11, 0)),
|
10.11,
|
||||||
}
|
}.Select(starRating => new StarRatingDisplay(new StarDifficulty(starRating, 0))
|
||||||
};
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestChangingStarRatingDisplay()
|
||||||
|
{
|
||||||
|
StarRatingDisplay starRating = null;
|
||||||
|
|
||||||
|
AddStep("load display", () => Child = starRating = new StarRatingDisplay(new StarDifficulty(5.55, 1))
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Scale = new Vector2(3f),
|
||||||
|
});
|
||||||
|
|
||||||
|
AddRepeatStep("set random value", () =>
|
||||||
|
{
|
||||||
|
starRating.Current.Value = new StarDifficulty(RNG.NextDouble(0.0, 11.0), 1);
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
AddSliderStep("set exact stars", 0.0, 11.0, 5.55, d =>
|
||||||
|
{
|
||||||
|
if (starRating != null)
|
||||||
|
starRating.Current.Value = new StarDifficulty(d, 1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,151 @@
|
|||||||
|
// 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 System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Screens.Menu;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.SongSelect
|
||||||
|
{
|
||||||
|
public class TestSceneBeatmapMetadataDisplay : OsuTestScene
|
||||||
|
{
|
||||||
|
private BeatmapMetadataDisplay display;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private BeatmapManager manager { get; set; }
|
||||||
|
|
||||||
|
[Cached(typeof(BeatmapDifficultyCache))]
|
||||||
|
private readonly TestBeatmapDifficultyCache testDifficultyCache = new TestBeatmapDifficultyCache();
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestLocal([Values("Beatmap", "Some long title and stuff")]
|
||||||
|
string title,
|
||||||
|
[Values("Trial", "Some1's very hardest difficulty")]
|
||||||
|
string version)
|
||||||
|
{
|
||||||
|
showMetadataForBeatmap(() => CreateWorkingBeatmap(new Beatmap
|
||||||
|
{
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
Metadata = new BeatmapMetadata
|
||||||
|
{
|
||||||
|
Title = title,
|
||||||
|
},
|
||||||
|
Version = version,
|
||||||
|
StarDifficulty = RNG.NextDouble(0, 10),
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestDelayedStarRating()
|
||||||
|
{
|
||||||
|
AddStep("block calculation", () => testDifficultyCache.BlockCalculation = true);
|
||||||
|
|
||||||
|
showMetadataForBeatmap(() => CreateWorkingBeatmap(new Beatmap
|
||||||
|
{
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
Metadata = new BeatmapMetadata
|
||||||
|
{
|
||||||
|
Title = "Heavy beatmap",
|
||||||
|
},
|
||||||
|
Version = "10k objects",
|
||||||
|
StarDifficulty = 99.99f,
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
AddStep("allow calculation", () => testDifficultyCache.BlockCalculation = false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestRandomFromDatabase()
|
||||||
|
{
|
||||||
|
showMetadataForBeatmap(() =>
|
||||||
|
{
|
||||||
|
var allBeatmapSets = manager.GetAllUsableBeatmapSets(IncludedDetails.Minimal);
|
||||||
|
if (allBeatmapSets.Count == 0)
|
||||||
|
return manager.DefaultBeatmap;
|
||||||
|
|
||||||
|
var randomBeatmapSet = allBeatmapSets[RNG.Next(0, allBeatmapSets.Count - 1)];
|
||||||
|
var randomBeatmap = randomBeatmapSet.Beatmaps[RNG.Next(0, randomBeatmapSet.Beatmaps.Count - 1)];
|
||||||
|
|
||||||
|
return manager.GetWorkingBeatmap(randomBeatmap);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showMetadataForBeatmap(Func<WorkingBeatmap> getBeatmap)
|
||||||
|
{
|
||||||
|
AddStep("setup display", () =>
|
||||||
|
{
|
||||||
|
var randomMods = Ruleset.Value.CreateInstance().GetAllMods().OrderBy(_ => RNG.Next()).Take(5).ToList();
|
||||||
|
|
||||||
|
OsuLogo logo = new OsuLogo { Scale = new Vector2(0.15f) };
|
||||||
|
|
||||||
|
Remove(testDifficultyCache);
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
testDifficultyCache,
|
||||||
|
display = new BeatmapMetadataDisplay(getBeatmap(), new Bindable<IReadOnlyList<Mod>>(randomMods), logo)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Alpha = 0f,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
display.FadeIn(400, Easing.OutQuint);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddWaitStep("wait a bit", 5);
|
||||||
|
|
||||||
|
AddStep("finish loading", () => display.Loading = false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestBeatmapDifficultyCache : BeatmapDifficultyCache
|
||||||
|
{
|
||||||
|
private TaskCompletionSource<bool> calculationBlocker;
|
||||||
|
|
||||||
|
private bool blockCalculation;
|
||||||
|
|
||||||
|
public bool BlockCalculation
|
||||||
|
{
|
||||||
|
get => blockCalculation;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == blockCalculation)
|
||||||
|
return;
|
||||||
|
|
||||||
|
blockCalculation = value;
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
calculationBlocker = new TaskCompletionSource<bool>();
|
||||||
|
else
|
||||||
|
calculationBlocker?.SetResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<StarDifficulty> GetDifficultyAsync(BeatmapInfo beatmapInfo, RulesetInfo rulesetInfo = null, IEnumerable<Mod> mods = null, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (blockCalculation)
|
||||||
|
await calculationBlocker.Task;
|
||||||
|
|
||||||
|
return await base.GetDifficultyAsync(beatmapInfo, rulesetInfo, mods, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -264,7 +264,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
private void moveLogoFacade()
|
private void moveLogoFacade()
|
||||||
{
|
{
|
||||||
if (!(logoFacade?.Transforms).Any() && !(transferContainer?.Transforms).Any())
|
if (!logoFacade.Transforms.Any() && !transferContainer.Transforms.Any())
|
||||||
{
|
{
|
||||||
Random random = new Random();
|
Random random = new Random();
|
||||||
trackingContainer.Delay(500).MoveTo(new Vector2(random.Next(0, (int)logo.Parent.DrawWidth), random.Next(0, (int)logo.Parent.DrawHeight)), 300);
|
trackingContainer.Delay(500).MoveTo(new Vector2(random.Next(0, (int)logo.Parent.DrawWidth), random.Next(0, (int)logo.Parent.DrawHeight)), 300);
|
||||||
|
@ -7,6 +7,7 @@ using System.Linq;
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
@ -77,8 +78,8 @@ namespace osu.Game.Tournament.IPC
|
|||||||
using (var stream = IPCStorage.GetStream(file_ipc_filename))
|
using (var stream = IPCStorage.GetStream(file_ipc_filename))
|
||||||
using (var sr = new StreamReader(stream))
|
using (var sr = new StreamReader(stream))
|
||||||
{
|
{
|
||||||
var beatmapId = int.Parse(sr.ReadLine());
|
var beatmapId = int.Parse(sr.ReadLine().AsNonNull());
|
||||||
var mods = int.Parse(sr.ReadLine());
|
var mods = int.Parse(sr.ReadLine().AsNonNull());
|
||||||
|
|
||||||
if (lastBeatmapId != beatmapId)
|
if (lastBeatmapId != beatmapId)
|
||||||
{
|
{
|
||||||
@ -124,7 +125,7 @@ namespace osu.Game.Tournament.IPC
|
|||||||
using (var stream = IPCStorage.GetStream(file_ipc_state_filename))
|
using (var stream = IPCStorage.GetStream(file_ipc_state_filename))
|
||||||
using (var sr = new StreamReader(stream))
|
using (var sr = new StreamReader(stream))
|
||||||
{
|
{
|
||||||
State.Value = (TourneyState)Enum.Parse(typeof(TourneyState), sr.ReadLine());
|
State.Value = (TourneyState)Enum.Parse(typeof(TourneyState), sr.ReadLine().AsNonNull());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
|
@ -103,8 +103,8 @@ namespace osu.Game.Beatmaps
|
|||||||
/// <param name="mods">The <see cref="Mod"/>s to get the difficulty with.</param>
|
/// <param name="mods">The <see cref="Mod"/>s to get the difficulty with.</param>
|
||||||
/// <param name="cancellationToken">An optional <see cref="CancellationToken"/> which stops computing the star difficulty.</param>
|
/// <param name="cancellationToken">An optional <see cref="CancellationToken"/> which stops computing the star difficulty.</param>
|
||||||
/// <returns>The <see cref="StarDifficulty"/>.</returns>
|
/// <returns>The <see cref="StarDifficulty"/>.</returns>
|
||||||
public Task<StarDifficulty> GetDifficultyAsync([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo rulesetInfo = null, [CanBeNull] IEnumerable<Mod> mods = null,
|
public virtual Task<StarDifficulty> GetDifficultyAsync([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo rulesetInfo = null,
|
||||||
CancellationToken cancellationToken = default)
|
[CanBeNull] IEnumerable<Mod> mods = null, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
// In the case that the user hasn't given us a ruleset, use the beatmap's default ruleset.
|
// In the case that the user hasn't given us a ruleset, use the beatmap's default ruleset.
|
||||||
rulesetInfo ??= beatmapInfo.Ruleset;
|
rulesetInfo ??= beatmapInfo.Ruleset;
|
||||||
|
@ -7,6 +7,7 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.IO.Serialization;
|
using osu.Game.IO.Serialization;
|
||||||
@ -127,6 +128,8 @@ namespace osu.Game.Beatmaps
|
|||||||
// Metadata
|
// Metadata
|
||||||
public string Version { get; set; }
|
public string Version { get; set; }
|
||||||
|
|
||||||
|
private string versionString => string.IsNullOrEmpty(Version) ? string.Empty : $"[{Version}]";
|
||||||
|
|
||||||
[JsonProperty("difficulty_rating")]
|
[JsonProperty("difficulty_rating")]
|
||||||
public double StarDifficulty { get; set; }
|
public double StarDifficulty { get; set; }
|
||||||
|
|
||||||
@ -143,11 +146,12 @@ namespace osu.Game.Beatmaps
|
|||||||
Version
|
Version
|
||||||
}.Concat(Metadata?.SearchableTerms ?? Enumerable.Empty<string>()).Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
}.Concat(Metadata?.SearchableTerms ?? Enumerable.Empty<string>()).Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString() => $"{Metadata ?? BeatmapSet?.Metadata} {versionString}".Trim();
|
||||||
{
|
|
||||||
string version = string.IsNullOrEmpty(Version) ? string.Empty : $"[{Version}]";
|
|
||||||
|
|
||||||
return $"{Metadata ?? BeatmapSet?.Metadata} {version}".Trim();
|
public RomanisableString ToRomanisableString()
|
||||||
|
{
|
||||||
|
var metadata = (Metadata ?? BeatmapSet?.Metadata)?.ToRomanisableString() ?? new RomanisableString(null, null);
|
||||||
|
return new RomanisableString($"{metadata.GetPreferred(true)} {versionString}".Trim(), $"{metadata.GetPreferred(false)} {versionString}".Trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Equals(BeatmapInfo other)
|
public bool Equals(BeatmapInfo other)
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// 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;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -83,6 +82,12 @@ namespace osu.Game.Beatmaps
|
|||||||
beatmap.BeatmapSet.OnlineBeatmapSetID = res.OnlineBeatmapSetID;
|
beatmap.BeatmapSet.OnlineBeatmapSetID = res.OnlineBeatmapSetID;
|
||||||
beatmap.OnlineBeatmapID = res.OnlineBeatmapID;
|
beatmap.OnlineBeatmapID = res.OnlineBeatmapID;
|
||||||
|
|
||||||
|
if (beatmap.Metadata != null)
|
||||||
|
beatmap.Metadata.AuthorID = res.AuthorID;
|
||||||
|
|
||||||
|
if (beatmap.BeatmapSet.Metadata != null)
|
||||||
|
beatmap.BeatmapSet.Metadata.AuthorID = res.AuthorID;
|
||||||
|
|
||||||
LogForModel(set, $"Online retrieval mapped {beatmap} to {res.OnlineBeatmapSetID} / {res.OnlineBeatmapID}.");
|
LogForModel(set, $"Online retrieval mapped {beatmap} to {res.OnlineBeatmapSetID} / {res.OnlineBeatmapID}.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,7 +162,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
using (var cmd = db.CreateCommand())
|
using (var cmd = db.CreateCommand())
|
||||||
{
|
{
|
||||||
cmd.CommandText = "SELECT beatmapset_id, beatmap_id, approved FROM osu_beatmaps WHERE checksum = @MD5Hash OR beatmap_id = @OnlineBeatmapID OR filename = @Path";
|
cmd.CommandText = "SELECT beatmapset_id, beatmap_id, approved, user_id FROM osu_beatmaps WHERE checksum = @MD5Hash OR beatmap_id = @OnlineBeatmapID OR filename = @Path";
|
||||||
|
|
||||||
cmd.Parameters.Add(new SqliteParameter("@MD5Hash", beatmap.MD5Hash));
|
cmd.Parameters.Add(new SqliteParameter("@MD5Hash", beatmap.MD5Hash));
|
||||||
cmd.Parameters.Add(new SqliteParameter("@OnlineBeatmapID", beatmap.OnlineBeatmapID ?? (object)DBNull.Value));
|
cmd.Parameters.Add(new SqliteParameter("@OnlineBeatmapID", beatmap.OnlineBeatmapID ?? (object)DBNull.Value));
|
||||||
@ -174,6 +179,12 @@ namespace osu.Game.Beatmaps
|
|||||||
beatmap.BeatmapSet.OnlineBeatmapSetID = reader.GetInt32(0);
|
beatmap.BeatmapSet.OnlineBeatmapSetID = reader.GetInt32(0);
|
||||||
beatmap.OnlineBeatmapID = reader.GetInt32(1);
|
beatmap.OnlineBeatmapID = reader.GetInt32(1);
|
||||||
|
|
||||||
|
if (beatmap.Metadata != null)
|
||||||
|
beatmap.Metadata.AuthorID = reader.GetInt32(3);
|
||||||
|
|
||||||
|
if (beatmap.BeatmapSet.Metadata != null)
|
||||||
|
beatmap.BeatmapSet.Metadata.AuthorID = reader.GetInt32(3);
|
||||||
|
|
||||||
LogForModel(set, $"Cached local retrieval for {beatmap}.");
|
LogForModel(set, $"Cached local retrieval for {beatmap}.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -194,17 +205,6 @@ namespace osu.Game.Beatmaps
|
|||||||
cacheDownloadRequest?.Dispose();
|
cacheDownloadRequest?.Dispose();
|
||||||
updateScheduler?.Dispose();
|
updateScheduler?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
|
||||||
private class CachedOnlineBeatmapLookup
|
|
||||||
{
|
|
||||||
public int approved { get; set; }
|
|
||||||
|
|
||||||
public int? beatmapset_id { get; set; }
|
|
||||||
|
|
||||||
public int? beatmap_id { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
@ -34,6 +35,21 @@ namespace osu.Game.Beatmaps
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public List<BeatmapSetInfo> BeatmapSets { get; set; }
|
public List<BeatmapSetInfo> BeatmapSets { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper property to deserialize a username to <see cref="User"/>.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty(@"user_id")]
|
||||||
|
[Column("AuthorID")]
|
||||||
|
public int AuthorID
|
||||||
|
{
|
||||||
|
get => Author?.Id ?? 1;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Author ??= new User();
|
||||||
|
Author.Id = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Helper property to deserialize a username to <see cref="User"/>.
|
/// Helper property to deserialize a username to <see cref="User"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -42,7 +58,11 @@ namespace osu.Game.Beatmaps
|
|||||||
public string AuthorString
|
public string AuthorString
|
||||||
{
|
{
|
||||||
get => Author?.Username;
|
get => Author?.Username;
|
||||||
set => Author = new User { Username = value };
|
set
|
||||||
|
{
|
||||||
|
Author ??= new User();
|
||||||
|
Author.Username = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -71,6 +91,12 @@ namespace osu.Game.Beatmaps
|
|||||||
return $"{Artist} - {Title} {author}".Trim();
|
return $"{Artist} - {Title} {author}".Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RomanisableString ToRomanisableString()
|
||||||
|
{
|
||||||
|
string author = Author == null ? string.Empty : $"({Author})";
|
||||||
|
return new RomanisableString($"{ArtistUnicode} - {TitleUnicode} {author}".Trim(), $"{Artist} - {Title} {author}".Trim());
|
||||||
|
}
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public string[] SearchableTerms => new[]
|
public string[] SearchableTerms => new[]
|
||||||
{
|
{
|
||||||
|
@ -472,7 +472,7 @@ namespace osu.Game.Database
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delete new file.
|
/// Delete an existing file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="model">The item to operate on.</param>
|
/// <param name="model">The item to operate on.</param>
|
||||||
/// <param name="file">The existing file to be deleted.</param>
|
/// <param name="file">The existing file to be deleted.</param>
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
|
using osu.Game.Screens.Play.HUD;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Extensions
|
namespace osu.Game.Extensions
|
||||||
@ -43,5 +45,23 @@ namespace osu.Game.Extensions
|
|||||||
/// <returns>The delta vector in Parent's coordinates.</returns>
|
/// <returns>The delta vector in Parent's coordinates.</returns>
|
||||||
public static Vector2 ScreenSpaceDeltaToParentSpace(this Drawable drawable, Vector2 delta) =>
|
public static Vector2 ScreenSpaceDeltaToParentSpace(this Drawable drawable, Vector2 delta) =>
|
||||||
drawable.Parent.ToLocalSpace(drawable.Parent.ToScreenSpace(Vector2.Zero) + delta);
|
drawable.Parent.ToLocalSpace(drawable.Parent.ToScreenSpace(Vector2.Zero) + delta);
|
||||||
|
|
||||||
|
public static SkinnableInfo CreateSkinnableInfo(this Drawable component) => new SkinnableInfo(component);
|
||||||
|
|
||||||
|
public static void ApplySkinnableInfo(this Drawable component, SkinnableInfo info)
|
||||||
|
{
|
||||||
|
// todo: can probably make this better via deserialisation directly using a common interface.
|
||||||
|
component.Position = info.Position;
|
||||||
|
component.Rotation = info.Rotation;
|
||||||
|
component.Scale = info.Scale;
|
||||||
|
component.Anchor = info.Anchor;
|
||||||
|
component.Origin = info.Origin;
|
||||||
|
|
||||||
|
if (component is Container container)
|
||||||
|
{
|
||||||
|
foreach (var child in info.Children)
|
||||||
|
container.Add(child.CreateInstance());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
|
|
||||||
namespace osu.Game.Extensions
|
namespace osu.Game.Extensions
|
||||||
{
|
{
|
||||||
@ -50,7 +51,7 @@ namespace osu.Game.Extensions
|
|||||||
}
|
}
|
||||||
else if (continuationTask.IsFaulted)
|
else if (continuationTask.IsFaulted)
|
||||||
{
|
{
|
||||||
tcs.TrySetException(continuationTask.Exception);
|
tcs.TrySetException(continuationTask.Exception.AsNonNull());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -7,7 +7,10 @@ using System.Linq;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.Containers
|
namespace osu.Game.Graphics.Containers
|
||||||
@ -59,6 +62,14 @@ namespace osu.Game.Graphics.Containers
|
|||||||
public void AddLink(string text, LinkAction action, string argument, string tooltipText = null, Action<SpriteText> creationParameters = null)
|
public void AddLink(string text, LinkAction action, string argument, string tooltipText = null, Action<SpriteText> creationParameters = null)
|
||||||
=> createLink(AddText(text, creationParameters), new LinkDetails(action, argument), tooltipText);
|
=> createLink(AddText(text, creationParameters), new LinkDetails(action, argument), tooltipText);
|
||||||
|
|
||||||
|
public void AddLink(LocalisableString text, LinkAction action, string argument, string tooltipText = null, Action<SpriteText> creationParameters = null)
|
||||||
|
{
|
||||||
|
var spriteText = new OsuSpriteText { Text = text };
|
||||||
|
|
||||||
|
AddText(spriteText, creationParameters);
|
||||||
|
createLink(spriteText.Yield(), new LinkDetails(action, argument), tooltipText);
|
||||||
|
}
|
||||||
|
|
||||||
public void AddLink(IEnumerable<SpriteText> text, LinkAction action = LinkAction.External, string linkArgument = null, string tooltipText = null)
|
public void AddLink(IEnumerable<SpriteText> text, LinkAction action = LinkAction.External, string linkArgument = null, string tooltipText = null)
|
||||||
{
|
{
|
||||||
foreach (var t in text)
|
foreach (var t in text)
|
||||||
|
18
osu.Game/Graphics/UserInterface/DangerousTriangleButton.cs
Normal file
18
osu.Game/Graphics/UserInterface/DangerousTriangleButton.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.UserInterface
|
||||||
|
{
|
||||||
|
public class DangerousTriangleButton : TriangleButton
|
||||||
|
{
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
BackgroundColour = colours.PinkDark;
|
||||||
|
Triangles.ColourDark = colours.PinkDarker;
|
||||||
|
Triangles.ColourLight = colours.Pink;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -38,6 +38,7 @@ namespace osu.Game.IO.Legacy
|
|||||||
/// <summary> Reads a string from the buffer. Overrides the base implementation so it can cope with nulls. </summary>
|
/// <summary> Reads a string from the buffer. Overrides the base implementation so it can cope with nulls. </summary>
|
||||||
public override string ReadString()
|
public override string ReadString()
|
||||||
{
|
{
|
||||||
|
// ReSharper disable once AssignNullToNotNullAttribute
|
||||||
if (ReadByte() == 0) return null;
|
if (ReadByte() == 0) return null;
|
||||||
|
|
||||||
return base.ReadString();
|
return base.ReadString();
|
||||||
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
|
|
||||||
namespace osu.Game.IO.Serialization.Converters
|
namespace osu.Game.IO.Serialization.Converters
|
||||||
{
|
{
|
||||||
@ -60,7 +61,7 @@ namespace osu.Game.IO.Serialization.Converters
|
|||||||
throw new JsonException("Expected $type token.");
|
throw new JsonException("Expected $type token.");
|
||||||
|
|
||||||
var typeName = lookupTable[(int)tok["$type"]];
|
var typeName = lookupTable[(int)tok["$type"]];
|
||||||
var instance = (T)Activator.CreateInstance(Type.GetType(typeName));
|
var instance = (T)Activator.CreateInstance(Type.GetType(typeName).AsNonNull());
|
||||||
serializer.Populate(itemReader, instance);
|
serializer.Populate(itemReader, instance);
|
||||||
|
|
||||||
list.Add(instance);
|
list.Add(instance);
|
||||||
|
@ -48,7 +48,7 @@ namespace osu.Game.Input.Bindings
|
|||||||
new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings),
|
new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleBeatmapListing),
|
new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleBeatmapListing),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.N }, GlobalAction.ToggleNotifications),
|
new KeyBinding(new[] { InputKey.Control, InputKey.N }, GlobalAction.ToggleNotifications),
|
||||||
new KeyBinding(new[] { InputKey.Shift, InputKey.F2 }, GlobalAction.ToggleSkinEditor),
|
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.S }, GlobalAction.ToggleSkinEditor),
|
||||||
|
|
||||||
new KeyBinding(InputKey.Escape, GlobalAction.Back),
|
new KeyBinding(InputKey.Escape, GlobalAction.Back),
|
||||||
new KeyBinding(InputKey.ExtraMouseButton1, GlobalAction.Back),
|
new KeyBinding(InputKey.ExtraMouseButton1, GlobalAction.Back),
|
||||||
|
511
osu.Game/Migrations/20210514062639_AddAuthorIdToBeatmapMetadata.Designer.cs
generated
Normal file
511
osu.Game/Migrations/20210514062639_AddAuthorIdToBeatmapMetadata.Designer.cs
generated
Normal file
@ -0,0 +1,511 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using osu.Game.Database;
|
||||||
|
|
||||||
|
namespace osu.Game.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(OsuDbContext))]
|
||||||
|
[Migration("20210514062639_AddAuthorIdToBeatmapMetadata")]
|
||||||
|
partial class AddAuthorIdToBeatmapMetadata
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "2.2.6-servicing-10079");
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<float>("ApproachRate");
|
||||||
|
|
||||||
|
b.Property<float>("CircleSize");
|
||||||
|
|
||||||
|
b.Property<float>("DrainRate");
|
||||||
|
|
||||||
|
b.Property<float>("OverallDifficulty");
|
||||||
|
|
||||||
|
b.Property<double>("SliderMultiplier");
|
||||||
|
|
||||||
|
b.Property<double>("SliderTickRate");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.ToTable("BeatmapDifficulty");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<double>("AudioLeadIn");
|
||||||
|
|
||||||
|
b.Property<double>("BPM");
|
||||||
|
|
||||||
|
b.Property<int>("BaseDifficultyID");
|
||||||
|
|
||||||
|
b.Property<int>("BeatDivisor");
|
||||||
|
|
||||||
|
b.Property<int>("BeatmapSetInfoID");
|
||||||
|
|
||||||
|
b.Property<bool>("Countdown");
|
||||||
|
|
||||||
|
b.Property<double>("DistanceSpacing");
|
||||||
|
|
||||||
|
b.Property<bool>("EpilepsyWarning");
|
||||||
|
|
||||||
|
b.Property<int>("GridSize");
|
||||||
|
|
||||||
|
b.Property<string>("Hash");
|
||||||
|
|
||||||
|
b.Property<bool>("Hidden");
|
||||||
|
|
||||||
|
b.Property<double>("Length");
|
||||||
|
|
||||||
|
b.Property<bool>("LetterboxInBreaks");
|
||||||
|
|
||||||
|
b.Property<string>("MD5Hash");
|
||||||
|
|
||||||
|
b.Property<int?>("MetadataID");
|
||||||
|
|
||||||
|
b.Property<int?>("OnlineBeatmapID");
|
||||||
|
|
||||||
|
b.Property<string>("Path");
|
||||||
|
|
||||||
|
b.Property<int>("RulesetID");
|
||||||
|
|
||||||
|
b.Property<bool>("SpecialStyle");
|
||||||
|
|
||||||
|
b.Property<float>("StackLeniency");
|
||||||
|
|
||||||
|
b.Property<double>("StarDifficulty");
|
||||||
|
|
||||||
|
b.Property<int>("Status");
|
||||||
|
|
||||||
|
b.Property<string>("StoredBookmarks");
|
||||||
|
|
||||||
|
b.Property<double>("TimelineZoom");
|
||||||
|
|
||||||
|
b.Property<string>("Version");
|
||||||
|
|
||||||
|
b.Property<bool>("WidescreenStoryboard");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("BaseDifficultyID");
|
||||||
|
|
||||||
|
b.HasIndex("BeatmapSetInfoID");
|
||||||
|
|
||||||
|
b.HasIndex("Hash");
|
||||||
|
|
||||||
|
b.HasIndex("MD5Hash");
|
||||||
|
|
||||||
|
b.HasIndex("MetadataID");
|
||||||
|
|
||||||
|
b.HasIndex("OnlineBeatmapID")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("RulesetID");
|
||||||
|
|
||||||
|
b.ToTable("BeatmapInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("Artist");
|
||||||
|
|
||||||
|
b.Property<string>("ArtistUnicode");
|
||||||
|
|
||||||
|
b.Property<string>("AudioFile");
|
||||||
|
|
||||||
|
b.Property<int>("AuthorID")
|
||||||
|
.HasColumnName("AuthorID");
|
||||||
|
|
||||||
|
b.Property<string>("AuthorString")
|
||||||
|
.HasColumnName("Author");
|
||||||
|
|
||||||
|
b.Property<string>("BackgroundFile");
|
||||||
|
|
||||||
|
b.Property<int>("PreviewTime");
|
||||||
|
|
||||||
|
b.Property<string>("Source");
|
||||||
|
|
||||||
|
b.Property<string>("Tags");
|
||||||
|
|
||||||
|
b.Property<string>("Title");
|
||||||
|
|
||||||
|
b.Property<string>("TitleUnicode");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.ToTable("BeatmapMetadata");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("BeatmapSetInfoID");
|
||||||
|
|
||||||
|
b.Property<int>("FileInfoID");
|
||||||
|
|
||||||
|
b.Property<string>("Filename")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("BeatmapSetInfoID");
|
||||||
|
|
||||||
|
b.HasIndex("FileInfoID");
|
||||||
|
|
||||||
|
b.ToTable("BeatmapSetFileInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<bool>("DeletePending");
|
||||||
|
|
||||||
|
b.Property<string>("Hash");
|
||||||
|
|
||||||
|
b.Property<int?>("MetadataID");
|
||||||
|
|
||||||
|
b.Property<int?>("OnlineBeatmapSetID");
|
||||||
|
|
||||||
|
b.Property<bool>("Protected");
|
||||||
|
|
||||||
|
b.Property<int>("Status");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("DeletePending");
|
||||||
|
|
||||||
|
b.HasIndex("Hash")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("MetadataID");
|
||||||
|
|
||||||
|
b.HasIndex("OnlineBeatmapSetID")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("BeatmapSetInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.HasColumnName("Key");
|
||||||
|
|
||||||
|
b.Property<int?>("RulesetID");
|
||||||
|
|
||||||
|
b.Property<int?>("SkinInfoID");
|
||||||
|
|
||||||
|
b.Property<string>("StringValue")
|
||||||
|
.HasColumnName("Value");
|
||||||
|
|
||||||
|
b.Property<int?>("Variant");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("SkinInfoID");
|
||||||
|
|
||||||
|
b.HasIndex("RulesetID", "Variant");
|
||||||
|
|
||||||
|
b.ToTable("Settings");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("Hash");
|
||||||
|
|
||||||
|
b.Property<int>("ReferenceCount");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("Hash")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("ReferenceCount");
|
||||||
|
|
||||||
|
b.ToTable("FileInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("IntAction")
|
||||||
|
.HasColumnName("Action");
|
||||||
|
|
||||||
|
b.Property<string>("KeysString")
|
||||||
|
.HasColumnName("Keys");
|
||||||
|
|
||||||
|
b.Property<int?>("RulesetID");
|
||||||
|
|
||||||
|
b.Property<int?>("Variant");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("IntAction");
|
||||||
|
|
||||||
|
b.HasIndex("RulesetID", "Variant");
|
||||||
|
|
||||||
|
b.ToTable("KeyBinding");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int?>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Available");
|
||||||
|
|
||||||
|
b.Property<string>("InstantiationInfo");
|
||||||
|
|
||||||
|
b.Property<string>("Name");
|
||||||
|
|
||||||
|
b.Property<string>("ShortName");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("Available");
|
||||||
|
|
||||||
|
b.HasIndex("ShortName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("RulesetInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("FileInfoID");
|
||||||
|
|
||||||
|
b.Property<string>("Filename")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Property<int?>("ScoreInfoID");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("FileInfoID");
|
||||||
|
|
||||||
|
b.HasIndex("ScoreInfoID");
|
||||||
|
|
||||||
|
b.ToTable("ScoreFileInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<double>("Accuracy")
|
||||||
|
.HasColumnType("DECIMAL(1,4)");
|
||||||
|
|
||||||
|
b.Property<int>("BeatmapInfoID");
|
||||||
|
|
||||||
|
b.Property<int>("Combo");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Date");
|
||||||
|
|
||||||
|
b.Property<bool>("DeletePending");
|
||||||
|
|
||||||
|
b.Property<string>("Hash");
|
||||||
|
|
||||||
|
b.Property<int>("MaxCombo");
|
||||||
|
|
||||||
|
b.Property<string>("ModsJson")
|
||||||
|
.HasColumnName("Mods");
|
||||||
|
|
||||||
|
b.Property<long?>("OnlineScoreID");
|
||||||
|
|
||||||
|
b.Property<double?>("PP");
|
||||||
|
|
||||||
|
b.Property<int>("Rank");
|
||||||
|
|
||||||
|
b.Property<int>("RulesetID");
|
||||||
|
|
||||||
|
b.Property<string>("StatisticsJson")
|
||||||
|
.HasColumnName("Statistics");
|
||||||
|
|
||||||
|
b.Property<long>("TotalScore");
|
||||||
|
|
||||||
|
b.Property<int?>("UserID")
|
||||||
|
.HasColumnName("UserID");
|
||||||
|
|
||||||
|
b.Property<string>("UserString")
|
||||||
|
.HasColumnName("User");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("BeatmapInfoID");
|
||||||
|
|
||||||
|
b.HasIndex("OnlineScoreID")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("RulesetID");
|
||||||
|
|
||||||
|
b.ToTable("ScoreInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("FileInfoID");
|
||||||
|
|
||||||
|
b.Property<string>("Filename")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Property<int>("SkinInfoID");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("FileInfoID");
|
||||||
|
|
||||||
|
b.HasIndex("SkinInfoID");
|
||||||
|
|
||||||
|
b.ToTable("SkinFileInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("Creator");
|
||||||
|
|
||||||
|
b.Property<bool>("DeletePending");
|
||||||
|
|
||||||
|
b.Property<string>("Hash");
|
||||||
|
|
||||||
|
b.Property<string>("InstantiationInfo");
|
||||||
|
|
||||||
|
b.Property<string>("Name");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("DeletePending");
|
||||||
|
|
||||||
|
b.HasIndex("Hash")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("SkinInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("BaseDifficultyID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet")
|
||||||
|
.WithMany("Beatmaps")
|
||||||
|
.HasForeignKey("BeatmapSetInfoID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
|
||||||
|
.WithMany("Beatmaps")
|
||||||
|
.HasForeignKey("MetadataID");
|
||||||
|
|
||||||
|
b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RulesetID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo")
|
||||||
|
.WithMany("Files")
|
||||||
|
.HasForeignKey("BeatmapSetInfoID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("FileInfoID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
|
||||||
|
.WithMany("BeatmapSets")
|
||||||
|
.HasForeignKey("MetadataID");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("osu.Game.Skinning.SkinInfo")
|
||||||
|
.WithMany("Settings")
|
||||||
|
.HasForeignKey("SkinInfoID");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("FileInfoID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("osu.Game.Scoring.ScoreInfo")
|
||||||
|
.WithMany("Files")
|
||||||
|
.HasForeignKey("ScoreInfoID");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap")
|
||||||
|
.WithMany("Scores")
|
||||||
|
.HasForeignKey("BeatmapInfoID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RulesetID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("FileInfoID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("osu.Game.Skinning.SkinInfo")
|
||||||
|
.WithMany("Files")
|
||||||
|
.HasForeignKey("SkinInfoID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace osu.Game.Migrations
|
||||||
|
{
|
||||||
|
public partial class AddAuthorIdToBeatmapMetadata : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "AuthorID",
|
||||||
|
table: "BeatmapMetadata",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "AuthorID",
|
||||||
|
table: "BeatmapMetadata");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -126,6 +126,9 @@ namespace osu.Game.Migrations
|
|||||||
|
|
||||||
b.Property<string>("AudioFile");
|
b.Property<string>("AudioFile");
|
||||||
|
|
||||||
|
b.Property<int>("AuthorID")
|
||||||
|
.HasColumnName("AuthorID");
|
||||||
|
|
||||||
b.Property<string>("AuthorString")
|
b.Property<string>("AuthorString")
|
||||||
.HasColumnName("Author");
|
.HasColumnName("Author");
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ namespace osu.Game.Online.API
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return JObject.Parse(req.GetResponseString()).SelectToken("form_error", true).AsNonNull().ToObject<RegistrationRequest.RegistrationRequestErrors>();
|
return JObject.Parse(req.GetResponseString().AsNonNull()).SelectToken("form_error", true).AsNonNull().ToObject<RegistrationRequest.RegistrationRequestErrors>();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Online.Chat
|
namespace osu.Game.Online.Chat
|
||||||
@ -20,7 +21,10 @@ namespace osu.Game.Online.Chat
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Each word part of a chat link (split for word-wrap support).
|
/// Each word part of a chat link (split for word-wrap support).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<Drawable> Parts;
|
public readonly List<Drawable> Parts;
|
||||||
|
|
||||||
|
[Resolved(CanBeNull = true)]
|
||||||
|
private OverlayColourProvider overlayColourProvider { get; set; }
|
||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parts.Any(d => d.ReceivePositionalInputAt(screenSpacePos));
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parts.Any(d => d.ReceivePositionalInputAt(screenSpacePos));
|
||||||
|
|
||||||
@ -34,7 +38,7 @@ namespace osu.Game.Online.Chat
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
IdleColour = colours.Blue;
|
IdleColour = overlayColourProvider?.Light2 ?? colours.Blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IEnumerable<Drawable> EffectTargets => Parts;
|
protected override IEnumerable<Drawable> EffectTargets => Parts;
|
||||||
|
@ -92,10 +92,6 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private UserLookupCache userLookupCache { get; set; } = null!;
|
private UserLookupCache userLookupCache { get; set; } = null!;
|
||||||
|
|
||||||
// Only exists for compatibility with old osu-server-spectator build.
|
|
||||||
// Todo: Can be removed on 2021/02/26.
|
|
||||||
private long defaultPlaylistItemId;
|
|
||||||
|
|
||||||
private Room? apiRoom;
|
private Room? apiRoom;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -143,7 +139,6 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
{
|
{
|
||||||
Room = joinedRoom;
|
Room = joinedRoom;
|
||||||
apiRoom = room;
|
apiRoom = room;
|
||||||
defaultPlaylistItemId = apiRoom.Playlist.FirstOrDefault()?.ID ?? 0;
|
|
||||||
foreach (var user in joinedRoom.Users)
|
foreach (var user in joinedRoom.Users)
|
||||||
updateUserPlayingState(user.UserID, user.State);
|
updateUserPlayingState(user.UserID, user.State);
|
||||||
}, cancellationSource.Token).ConfigureAwait(false);
|
}, cancellationSource.Token).ConfigureAwait(false);
|
||||||
@ -581,7 +576,7 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
|
|
||||||
void updateItem(PlaylistItem item)
|
void updateItem(PlaylistItem item)
|
||||||
{
|
{
|
||||||
item.ID = settings.PlaylistItemId == 0 ? defaultPlaylistItemId : settings.PlaylistItemId;
|
item.ID = settings.PlaylistItemId;
|
||||||
item.Beatmap.Value = beatmap;
|
item.Beatmap.Value = beatmap;
|
||||||
item.Ruleset.Value = ruleset.RulesetInfo;
|
item.Ruleset.Value = ruleset.RulesetInfo;
|
||||||
item.RequiredMods.Clear();
|
item.RequiredMods.Clear();
|
||||||
|
@ -24,7 +24,13 @@ namespace osu.Game.Online.Spectator
|
|||||||
[Key(2)]
|
[Key(2)]
|
||||||
public IEnumerable<APIMod> Mods { get; set; } = Enumerable.Empty<APIMod>();
|
public IEnumerable<APIMod> Mods { get; set; } = Enumerable.Empty<APIMod>();
|
||||||
|
|
||||||
public bool Equals(SpectatorState other) => BeatmapID == other?.BeatmapID && Mods.SequenceEqual(other?.Mods) && RulesetID == other?.RulesetID;
|
public bool Equals(SpectatorState other)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, other)) return false;
|
||||||
|
if (ReferenceEquals(this, other)) return true;
|
||||||
|
|
||||||
|
return BeatmapID == other.BeatmapID && Mods.SequenceEqual(other.Mods) && RulesetID == other.RulesetID;
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString() => $"Beatmap:{BeatmapID} Mods:{string.Join(',', Mods)} Ruleset:{RulesetID}";
|
public override string ToString() => $"Beatmap:{BeatmapID} Mods:{string.Join(',', Mods)} Ruleset:{RulesetID}";
|
||||||
}
|
}
|
||||||
|
@ -339,22 +339,13 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ClearButton : TriangleButton
|
public class ClearButton : DangerousTriangleButton
|
||||||
{
|
{
|
||||||
public ClearButton()
|
public ClearButton()
|
||||||
{
|
{
|
||||||
Text = "Clear";
|
Text = "Clear";
|
||||||
Size = new Vector2(80, 20);
|
Size = new Vector2(80, 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
BackgroundColour = colours.Pink;
|
|
||||||
|
|
||||||
Triangles.ColourDark = colours.PinkDark;
|
|
||||||
Triangles.ColourLight = colours.PinkLight;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class KeyButton : Container
|
public class KeyButton : Container
|
||||||
|
@ -11,7 +11,6 @@ using osu.Game.Input;
|
|||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osu.Game.Graphics;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.KeyBinding
|
namespace osu.Game.Overlays.KeyBinding
|
||||||
{
|
{
|
||||||
@ -55,10 +54,10 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ResetButton : TriangleButton
|
public class ResetButton : DangerousTriangleButton
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load()
|
||||||
{
|
{
|
||||||
Text = "Reset all bindings in section";
|
Text = "Reset all bindings in section";
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
@ -66,10 +65,6 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
Height = 20;
|
Height = 20;
|
||||||
|
|
||||||
Content.CornerRadius = 5;
|
Content.CornerRadius = 5;
|
||||||
|
|
||||||
BackgroundColour = colours.PinkDark;
|
|
||||||
Triangles.ColourDark = colours.PinkDarker;
|
|
||||||
Triangles.ColourLight = colours.Pink;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,128 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using System.IO;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
|
using osu.Game.Screens;
|
||||||
|
using osuTK;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Framework.Screens;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||||
|
{
|
||||||
|
public abstract class DirectorySelectScreen : OsuScreen
|
||||||
|
{
|
||||||
|
private TriangleButton selectionButton;
|
||||||
|
|
||||||
|
private DirectorySelector directorySelector;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Text to display in the header to inform the user of what they are selecting.
|
||||||
|
/// </summary>
|
||||||
|
public abstract LocalisableString HeaderText { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called upon selection of a directory by the user.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="directory">The selected directory</param>
|
||||||
|
protected abstract void OnSelection(DirectoryInfo directory);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the current directory is considered to be valid and can be selected.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="info">The current directory.</param>
|
||||||
|
/// <returns>Whether the selected directory is considered valid.</returns>
|
||||||
|
protected virtual bool IsValidDirectory(DirectoryInfo info) => true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The path at which to start selection from.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual DirectoryInfo InitialPath => null;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
InternalChild = new Container
|
||||||
|
{
|
||||||
|
Masking = true,
|
||||||
|
CornerRadius = 10,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Size = new Vector2(0.5f, 0.8f),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colours.GreySeafoamDark
|
||||||
|
},
|
||||||
|
new GridContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
RowDimensions = new[]
|
||||||
|
{
|
||||||
|
new Dimension(),
|
||||||
|
new Dimension(GridSizeMode.Relative, 0.8f),
|
||||||
|
new Dimension(),
|
||||||
|
},
|
||||||
|
Content = new[]
|
||||||
|
{
|
||||||
|
new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Text = HeaderText,
|
||||||
|
Font = OsuFont.Default.With(size: 40),
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Drawable[]
|
||||||
|
{
|
||||||
|
directorySelector = new DirectorySelector
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Drawable[]
|
||||||
|
{
|
||||||
|
selectionButton = new TriangleButton
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Width = 300,
|
||||||
|
Text = "Select directory",
|
||||||
|
Action = () => OnSelection(directorySelector.CurrentPath.Value)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
if (InitialPath != null)
|
||||||
|
directorySelector.CurrentPath.Value = InitialPath;
|
||||||
|
|
||||||
|
directorySelector.CurrentPath.BindValueChanged(e => selectionButton.Enabled.Value = e.NewValue != null && IsValidDirectory(e.NewValue), true);
|
||||||
|
base.LoadComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnSuspending(IScreen next)
|
||||||
|
{
|
||||||
|
base.OnSuspending(next);
|
||||||
|
|
||||||
|
this.FadeOut(250);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,24 +4,19 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Localisation;
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Graphics.Sprites;
|
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
using osu.Game.Graphics.UserInterfaceV2;
|
|
||||||
using osu.Game.Screens;
|
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||||
{
|
{
|
||||||
public class MigrationSelectScreen : OsuScreen
|
public class MigrationSelectScreen : DirectorySelectScreen
|
||||||
{
|
{
|
||||||
private DirectorySelector directorySelector;
|
[Resolved]
|
||||||
|
private Storage storage { get; set; }
|
||||||
|
|
||||||
|
protected override DirectoryInfo InitialPath => new DirectoryInfo(storage.GetFullPath(string.Empty)).Parent;
|
||||||
|
|
||||||
public override bool AllowExternalScreenChange => false;
|
public override bool AllowExternalScreenChange => false;
|
||||||
|
|
||||||
@ -29,84 +24,11 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
|||||||
|
|
||||||
public override bool HideOverlaysOnEnter => true;
|
public override bool HideOverlaysOnEnter => true;
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
public override LocalisableString HeaderText => "Please select a new location";
|
||||||
private void load(OsuGame game, Storage storage, OsuColour colours)
|
|
||||||
|
protected override void OnSelection(DirectoryInfo directory)
|
||||||
{
|
{
|
||||||
game?.Toolbar.Hide();
|
var target = directory;
|
||||||
|
|
||||||
// begin selection in the parent directory of the current storage location
|
|
||||||
var initialPath = new DirectoryInfo(storage.GetFullPath(string.Empty)).Parent?.FullName;
|
|
||||||
|
|
||||||
InternalChild = new Container
|
|
||||||
{
|
|
||||||
Masking = true,
|
|
||||||
CornerRadius = 10,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Size = new Vector2(0.5f, 0.8f),
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
Colour = colours.GreySeafoamDark,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
},
|
|
||||||
new GridContainer
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
RowDimensions = new[]
|
|
||||||
{
|
|
||||||
new Dimension(),
|
|
||||||
new Dimension(GridSizeMode.Relative, 0.8f),
|
|
||||||
new Dimension(),
|
|
||||||
},
|
|
||||||
Content = new[]
|
|
||||||
{
|
|
||||||
new Drawable[]
|
|
||||||
{
|
|
||||||
new OsuSpriteText
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Text = "Please select a new location",
|
|
||||||
Font = OsuFont.Default.With(size: 40)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
new Drawable[]
|
|
||||||
{
|
|
||||||
directorySelector = new DirectorySelector(initialPath)
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new Drawable[]
|
|
||||||
{
|
|
||||||
new TriangleButton
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Width = 300,
|
|
||||||
Text = "Begin folder migration",
|
|
||||||
Action = start
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnSuspending(IScreen next)
|
|
||||||
{
|
|
||||||
base.OnSuspending(next);
|
|
||||||
|
|
||||||
this.FadeOut(250);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void start()
|
|
||||||
{
|
|
||||||
var target = directorySelector.CurrentPath.Value;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Edit.Checks;
|
using osu.Game.Rulesets.Edit.Checks;
|
||||||
using osu.Game.Rulesets.Edit.Checks.Components;
|
using osu.Game.Rulesets.Edit.Checks.Components;
|
||||||
|
|
||||||
@ -29,9 +28,9 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
new CheckConcurrentObjects()
|
new CheckConcurrentObjects()
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, WorkingBeatmap workingBeatmap)
|
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||||
{
|
{
|
||||||
return checks.SelectMany(check => check.Run(playableBeatmap, workingBeatmap));
|
return checks.SelectMany(check => check.Run(context));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
38
osu.Game/Rulesets/Edit/BeatmapVerifierContext.cs
Normal file
38
osu.Game/Rulesets/Edit/BeatmapVerifierContext.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// 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.Beatmaps;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Edit
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the context provided by the beatmap verifier to the checks it runs.
|
||||||
|
/// Contains information about what is being checked and how it should be checked.
|
||||||
|
/// </summary>
|
||||||
|
public class BeatmapVerifierContext
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The playable beatmap instance of the current beatmap.
|
||||||
|
/// </summary>
|
||||||
|
public readonly IBeatmap Beatmap;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The working beatmap instance of the current beatmap.
|
||||||
|
/// </summary>
|
||||||
|
public readonly IWorkingBeatmap WorkingBeatmap;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The difficulty level which the current beatmap is considered to be.
|
||||||
|
/// </summary>
|
||||||
|
public DifficultyRating InterpretedDifficulty;
|
||||||
|
|
||||||
|
public BeatmapVerifierContext(IBeatmap beatmap, IWorkingBeatmap workingBeatmap, DifficultyRating difficultyRating = DifficultyRating.ExpertPlus)
|
||||||
|
{
|
||||||
|
Beatmap = beatmap;
|
||||||
|
WorkingBeatmap = workingBeatmap;
|
||||||
|
InterpretedDifficulty = difficultyRating;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,6 @@ namespace osu.Game.Rulesets.Edit.Checks
|
|||||||
{
|
{
|
||||||
protected override CheckCategory Category => CheckCategory.Audio;
|
protected override CheckCategory Category => CheckCategory.Audio;
|
||||||
protected override string TypeOfFile => "audio";
|
protected override string TypeOfFile => "audio";
|
||||||
protected override string GetFilename(IBeatmap playableBeatmap) => playableBeatmap.Metadata?.AudioFile;
|
protected override string GetFilename(IBeatmap beatmap) => beatmap.Metadata?.AudioFile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// 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.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Edit.Checks.Components;
|
using osu.Game.Rulesets.Edit.Checks.Components;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Edit.Checks
|
namespace osu.Game.Rulesets.Edit.Checks
|
||||||
@ -26,13 +25,13 @@ namespace osu.Game.Rulesets.Edit.Checks
|
|||||||
new IssueTemplateNoBitrate(this)
|
new IssueTemplateNoBitrate(this)
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, IWorkingBeatmap workingBeatmap)
|
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||||
{
|
{
|
||||||
var audioFile = playableBeatmap.Metadata?.AudioFile;
|
var audioFile = context.Beatmap.Metadata?.AudioFile;
|
||||||
if (audioFile == null)
|
if (audioFile == null)
|
||||||
yield break;
|
yield break;
|
||||||
|
|
||||||
var track = workingBeatmap.Track;
|
var track = context.WorkingBeatmap.Track;
|
||||||
|
|
||||||
if (track?.Bitrate == null || track.Bitrate.Value == 0)
|
if (track?.Bitrate == null || track.Bitrate.Value == 0)
|
||||||
yield return new IssueTemplateNoBitrate(this).Create();
|
yield return new IssueTemplateNoBitrate(this).Create();
|
||||||
|
@ -10,6 +10,6 @@ namespace osu.Game.Rulesets.Edit.Checks
|
|||||||
{
|
{
|
||||||
protected override CheckCategory Category => CheckCategory.Resources;
|
protected override CheckCategory Category => CheckCategory.Resources;
|
||||||
protected override string TypeOfFile => "background";
|
protected override string TypeOfFile => "background";
|
||||||
protected override string GetFilename(IBeatmap playableBeatmap) => playableBeatmap.Metadata?.BackgroundFile;
|
protected override string GetFilename(IBeatmap beatmap) => beatmap.Metadata?.BackgroundFile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// 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.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Edit.Checks.Components;
|
using osu.Game.Rulesets.Edit.Checks.Components;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Edit.Checks
|
namespace osu.Game.Rulesets.Edit.Checks
|
||||||
@ -30,13 +29,13 @@ namespace osu.Game.Rulesets.Edit.Checks
|
|||||||
new IssueTemplateTooUncompressed(this)
|
new IssueTemplateTooUncompressed(this)
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, IWorkingBeatmap workingBeatmap)
|
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||||
{
|
{
|
||||||
var backgroundFile = playableBeatmap.Metadata?.BackgroundFile;
|
var backgroundFile = context.Beatmap.Metadata?.BackgroundFile;
|
||||||
if (backgroundFile == null)
|
if (backgroundFile == null)
|
||||||
yield break;
|
yield break;
|
||||||
|
|
||||||
var texture = workingBeatmap.Background;
|
var texture = context.WorkingBeatmap.Background;
|
||||||
if (texture == null)
|
if (texture == null)
|
||||||
yield break;
|
yield break;
|
||||||
|
|
||||||
@ -48,8 +47,8 @@ namespace osu.Game.Rulesets.Edit.Checks
|
|||||||
else if (texture.Width < low_width || texture.Height < low_height)
|
else if (texture.Width < low_width || texture.Height < low_height)
|
||||||
yield return new IssueTemplateLowResolution(this).Create(texture.Width, texture.Height);
|
yield return new IssueTemplateLowResolution(this).Create(texture.Width, texture.Height);
|
||||||
|
|
||||||
string storagePath = playableBeatmap.BeatmapInfo.BeatmapSet.GetPathForFile(backgroundFile);
|
string storagePath = context.Beatmap.BeatmapInfo.BeatmapSet.GetPathForFile(backgroundFile);
|
||||||
double filesizeMb = workingBeatmap.GetStream(storagePath).Length / (1024d * 1024d);
|
double filesizeMb = context.WorkingBeatmap.GetStream(storagePath).Length / (1024d * 1024d);
|
||||||
|
|
||||||
if (filesizeMb > max_filesize_mb)
|
if (filesizeMb > max_filesize_mb)
|
||||||
yield return new IssueTemplateTooUncompressed(this).Create(filesizeMb);
|
yield return new IssueTemplateTooUncompressed(this).Create(filesizeMb);
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// 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.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Edit.Checks.Components;
|
using osu.Game.Rulesets.Edit.Checks.Components;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
@ -22,15 +21,17 @@ namespace osu.Game.Rulesets.Edit.Checks
|
|||||||
new IssueTemplateConcurrentDifferent(this)
|
new IssueTemplateConcurrentDifferent(this)
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, IWorkingBeatmap workingBeatmap)
|
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < playableBeatmap.HitObjects.Count - 1; ++i)
|
var hitObjects = context.Beatmap.HitObjects;
|
||||||
{
|
|
||||||
var hitobject = playableBeatmap.HitObjects[i];
|
|
||||||
|
|
||||||
for (int j = i + 1; j < playableBeatmap.HitObjects.Count; ++j)
|
for (int i = 0; i < hitObjects.Count - 1; ++i)
|
||||||
|
{
|
||||||
|
var hitobject = hitObjects[i];
|
||||||
|
|
||||||
|
for (int j = i + 1; j < hitObjects.Count; ++j)
|
||||||
{
|
{
|
||||||
var nextHitobject = playableBeatmap.HitObjects[j];
|
var nextHitobject = hitObjects[j];
|
||||||
|
|
||||||
// Accounts for rulesets with hitobjects separated by columns, such as Mania.
|
// Accounts for rulesets with hitobjects separated by columns, such as Mania.
|
||||||
// In these cases we only care about concurrent objects within the same column.
|
// In these cases we only care about concurrent objects within the same column.
|
||||||
|
@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Edit.Checks
|
|||||||
{
|
{
|
||||||
protected abstract CheckCategory Category { get; }
|
protected abstract CheckCategory Category { get; }
|
||||||
protected abstract string TypeOfFile { get; }
|
protected abstract string TypeOfFile { get; }
|
||||||
protected abstract string GetFilename(IBeatmap playableBeatmap);
|
protected abstract string GetFilename(IBeatmap beatmap);
|
||||||
|
|
||||||
public CheckMetadata Metadata => new CheckMetadata(Category, $"Missing {TypeOfFile}");
|
public CheckMetadata Metadata => new CheckMetadata(Category, $"Missing {TypeOfFile}");
|
||||||
|
|
||||||
@ -21,9 +21,9 @@ namespace osu.Game.Rulesets.Edit.Checks
|
|||||||
new IssueTemplateDoesNotExist(this)
|
new IssueTemplateDoesNotExist(this)
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, IWorkingBeatmap workingBeatmap)
|
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||||
{
|
{
|
||||||
var filename = GetFilename(playableBeatmap);
|
var filename = GetFilename(context.Beatmap);
|
||||||
|
|
||||||
if (filename == null)
|
if (filename == null)
|
||||||
{
|
{
|
||||||
@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Edit.Checks
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the file is set, also make sure it still exists.
|
// If the file is set, also make sure it still exists.
|
||||||
var storagePath = playableBeatmap.BeatmapInfo.BeatmapSet.GetPathForFile(filename);
|
var storagePath = context.Beatmap.BeatmapInfo.BeatmapSet.GetPathForFile(filename);
|
||||||
if (storagePath != null)
|
if (storagePath != null)
|
||||||
yield break;
|
yield break;
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Edit.Checks.Components;
|
using osu.Game.Rulesets.Edit.Checks.Components;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
@ -22,11 +21,11 @@ namespace osu.Game.Rulesets.Edit.Checks
|
|||||||
new IssueTemplateSmallUnsnap(this)
|
new IssueTemplateSmallUnsnap(this)
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, IWorkingBeatmap workingBeatmap)
|
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||||
{
|
{
|
||||||
var controlPointInfo = playableBeatmap.ControlPointInfo;
|
var controlPointInfo = context.Beatmap.ControlPointInfo;
|
||||||
|
|
||||||
foreach (var hitobject in playableBeatmap.HitObjects)
|
foreach (var hitobject in context.Beatmap.HitObjects)
|
||||||
{
|
{
|
||||||
double startUnsnap = hitobject.StartTime - controlPointInfo.GetClosestSnappedTime(hitobject.StartTime);
|
double startUnsnap = hitobject.StartTime - controlPointInfo.GetClosestSnappedTime(hitobject.StartTime);
|
||||||
string startPostfix = hitobject is IHasDuration ? "start" : "";
|
string startPostfix = hitobject is IHasDuration ? "start" : "";
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// 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.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Edit.Checks.Components
|
namespace osu.Game.Rulesets.Edit.Checks.Components
|
||||||
{
|
{
|
||||||
@ -24,8 +23,7 @@ namespace osu.Game.Rulesets.Edit.Checks.Components
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs this check and returns any issues detected for the provided beatmap.
|
/// Runs this check and returns any issues detected for the provided beatmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="playableBeatmap">The playable beatmap of the beatmap to run the check on.</param>
|
/// <param name="context">The beatmap verifier context associated with the beatmap.</param>
|
||||||
/// <param name="workingBeatmap">The working beatmap of the beatmap to run the check on.</param>
|
public IEnumerable<Issue> Run(BeatmapVerifierContext context);
|
||||||
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, IWorkingBeatmap workingBeatmap);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// 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.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Edit.Checks.Components;
|
using osu.Game.Rulesets.Edit.Checks.Components;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Edit
|
namespace osu.Game.Rulesets.Edit
|
||||||
@ -12,6 +11,6 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IBeatmapVerifier
|
public interface IBeatmapVerifier
|
||||||
{
|
{
|
||||||
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, WorkingBeatmap workingBeatmap);
|
public IEnumerable<Issue> Run(BeatmapVerifierContext context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
@ -18,14 +16,6 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
public override ModType Type => ModType.DifficultyIncrease;
|
public override ModType Type => ModType.DifficultyIncrease;
|
||||||
public override bool Ranked => true;
|
public override bool Ranked => true;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Check whether the provided hitobject should be considered the "first" hideable object.
|
|
||||||
/// Can be used to skip spinners, for instance.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hitObject">The hitobject to check.</param>
|
|
||||||
[Obsolete("Use IsFirstAdjustableObject() instead.")] // Can be removed 20210506
|
|
||||||
protected virtual bool IsFirstHideableObject(DrawableHitObject hitObject) => true;
|
|
||||||
|
|
||||||
public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
|
public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
|
||||||
{
|
{
|
||||||
// Default value of ScoreProcessor's Rank in Hidden Mod should be SS+
|
// Default value of ScoreProcessor's Rank in Hidden Mod should be SS+
|
||||||
@ -46,39 +36,5 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
return rank;
|
return rank;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
|
||||||
{
|
|
||||||
#pragma warning disable 618
|
|
||||||
ApplyFirstObjectIncreaseVisibilityState(hitObject, state);
|
|
||||||
#pragma warning restore 618
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
|
||||||
{
|
|
||||||
#pragma warning disable 618
|
|
||||||
ApplyHiddenState(hitObject, state);
|
|
||||||
#pragma warning restore 618
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Apply a special visibility state to the first object in a beatmap, if the user chooses to turn on the "increase first object visibility" setting.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hitObject">The hit object to apply the state change to.</param>
|
|
||||||
/// <param name="state">The state of the hit object.</param>
|
|
||||||
[Obsolete("Use ApplyIncreasedVisibilityState() instead.")] // Can be removed 20210506
|
|
||||||
protected virtual void ApplyFirstObjectIncreaseVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Apply a hidden state to the provided object.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hitObject">The hit object to apply the state change to.</param>
|
|
||||||
/// <param name="state">The state of the hit object.</param>
|
|
||||||
[Obsolete("Use ApplyNormalVisibilityState() instead.")] // Can be removed 20210506
|
|
||||||
protected virtual void ApplyHiddenState(DrawableHitObject hitObject, ArmedState state)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets
|
namespace osu.Game.Rulesets
|
||||||
@ -27,7 +28,7 @@ namespace osu.Game.Rulesets
|
|||||||
{
|
{
|
||||||
if (!Available) return null;
|
if (!Available) return null;
|
||||||
|
|
||||||
var ruleset = (Ruleset)Activator.CreateInstance(Type.GetType(InstantiationInfo));
|
var ruleset = (Ruleset)Activator.CreateInstance(Type.GetType(InstantiationInfo).AsNonNull());
|
||||||
|
|
||||||
// overwrite the pre-populated RulesetInfo with a potentially database attached copy.
|
// overwrite the pre-populated RulesetInfo with a potentially database attached copy.
|
||||||
ruleset.RulesetInfo = this;
|
ruleset.RulesetInfo = this;
|
||||||
|
@ -7,6 +7,7 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
@ -111,7 +112,7 @@ namespace osu.Game.Rulesets
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var instanceInfo = ((Ruleset)Activator.CreateInstance(Type.GetType(r.InstantiationInfo))).RulesetInfo;
|
var instanceInfo = ((Ruleset)Activator.CreateInstance(Type.GetType(r.InstantiationInfo).AsNonNull())).RulesetInfo;
|
||||||
|
|
||||||
r.Name = instanceInfo.Name;
|
r.Name = instanceInfo.Name;
|
||||||
r.ShortName = instanceInfo.ShortName;
|
r.ShortName = instanceInfo.ShortName;
|
||||||
|
@ -354,8 +354,11 @@ namespace osu.Game.Rulesets.UI
|
|||||||
|
|
||||||
// If this is the first time this DHO is being used, then apply the DHO mods.
|
// If this is the first time this DHO is being used, then apply the DHO mods.
|
||||||
// This is done before Apply() so that the state is updated once when the hitobject is applied.
|
// This is done before Apply() so that the state is updated once when the hitobject is applied.
|
||||||
foreach (var m in mods.OfType<IApplicableToDrawableHitObjects>())
|
if (mods != null)
|
||||||
m.ApplyToDrawableHitObjects(dho.Yield());
|
{
|
||||||
|
foreach (var m in mods.OfType<IApplicableToDrawableHitObjects>())
|
||||||
|
m.ApplyToDrawableHitObjects(dho.Yield());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lifetimeEntryMap.TryGetValue(hitObject, out var entry))
|
if (!lifetimeEntryMap.TryGetValue(hitObject, out var entry))
|
||||||
|
@ -3,9 +3,11 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
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.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
@ -24,6 +26,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
/// Includes selection and manipulation support via a <see cref="Components.SelectionHandler{T}"/>.
|
/// Includes selection and manipulation support via a <see cref="Components.SelectionHandler{T}"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class BlueprintContainer<T> : CompositeDrawable, IKeyBindingHandler<PlatformAction>
|
public abstract class BlueprintContainer<T> : CompositeDrawable, IKeyBindingHandler<PlatformAction>
|
||||||
|
where T : class
|
||||||
{
|
{
|
||||||
protected DragBox DragBox { get; private set; }
|
protected DragBox DragBox { get; private set; }
|
||||||
|
|
||||||
@ -39,6 +42,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private IEditorChangeHandler changeHandler { get; set; }
|
private IEditorChangeHandler changeHandler { get; set; }
|
||||||
|
|
||||||
|
protected readonly BindableList<T> SelectedItems = new BindableList<T>();
|
||||||
|
|
||||||
protected BlueprintContainer()
|
protected BlueprintContainer()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
@ -47,6 +52,24 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
|
SelectedItems.CollectionChanged += (selectedObjects, args) =>
|
||||||
|
{
|
||||||
|
switch (args.Action)
|
||||||
|
{
|
||||||
|
case NotifyCollectionChangedAction.Add:
|
||||||
|
foreach (var o in args.NewItems)
|
||||||
|
SelectionBlueprints.FirstOrDefault(b => b.Item == o)?.Select();
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NotifyCollectionChangedAction.Remove:
|
||||||
|
foreach (var o in args.OldItems)
|
||||||
|
SelectionBlueprints.FirstOrDefault(b => b.Item == o)?.Deselect();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
SelectionHandler = CreateSelectionHandler();
|
SelectionHandler = CreateSelectionHandler();
|
||||||
SelectionHandler.DeselectAll = deselectAll;
|
SelectionHandler.DeselectAll = deselectAll;
|
||||||
|
|
||||||
|
@ -2,10 +2,8 @@
|
|||||||
// 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.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
|
||||||
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.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
@ -25,7 +23,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
protected readonly HitObjectComposer Composer;
|
protected readonly HitObjectComposer Composer;
|
||||||
|
|
||||||
private readonly BindableList<HitObject> selectedHitObjects = new BindableList<HitObject>();
|
private HitObjectUsageEventBuffer usageEventBuffer;
|
||||||
|
|
||||||
protected EditorBlueprintContainer(HitObjectComposer composer)
|
protected EditorBlueprintContainer(HitObjectComposer composer)
|
||||||
{
|
{
|
||||||
@ -35,23 +33,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
selectedHitObjects.BindTo(Beatmap.SelectedHitObjects);
|
SelectedItems.BindTo(Beatmap.SelectedHitObjects);
|
||||||
selectedHitObjects.CollectionChanged += (selectedObjects, args) =>
|
|
||||||
{
|
|
||||||
switch (args.Action)
|
|
||||||
{
|
|
||||||
case NotifyCollectionChangedAction.Add:
|
|
||||||
foreach (var o in args.NewItems)
|
|
||||||
SelectionBlueprints.FirstOrDefault(b => b.Item == o)?.Select();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NotifyCollectionChangedAction.Remove:
|
|
||||||
foreach (var o in args.OldItems)
|
|
||||||
SelectionBlueprints.FirstOrDefault(b => b.Item == o)?.Deselect();
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -66,14 +48,19 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
foreach (var obj in Composer.HitObjects)
|
foreach (var obj in Composer.HitObjects)
|
||||||
AddBlueprintFor(obj.HitObject);
|
AddBlueprintFor(obj.HitObject);
|
||||||
|
|
||||||
var eventQueue = new HitObjectContainerEventQueue(Composer.Playfield);
|
usageEventBuffer = new HitObjectUsageEventBuffer(Composer.Playfield);
|
||||||
eventQueue.HitObjectUsageBegan += AddBlueprintFor;
|
usageEventBuffer.HitObjectUsageBegan += AddBlueprintFor;
|
||||||
eventQueue.HitObjectUsageFinished += RemoveBlueprintFor;
|
usageEventBuffer.HitObjectUsageFinished += RemoveBlueprintFor;
|
||||||
eventQueue.HitObjectUsageTransferred += TransferBlueprintFor;
|
usageEventBuffer.HitObjectUsageTransferred += TransferBlueprintFor;
|
||||||
AddInternal(eventQueue);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
usageEventBuffer?.Update();
|
||||||
|
}
|
||||||
|
|
||||||
protected override IEnumerable<SelectionBlueprint<HitObject>> SortForMovement(IReadOnlyList<SelectionBlueprint<HitObject>> blueprints)
|
protected override IEnumerable<SelectionBlueprint<HitObject>> SortForMovement(IReadOnlyList<SelectionBlueprint<HitObject>> blueprints)
|
||||||
=> blueprints.OrderBy(b => b.Item.StartTime);
|
=> blueprints.OrderBy(b => b.Item.StartTime);
|
||||||
|
|
||||||
@ -104,6 +91,11 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
base.AddBlueprintFor(item);
|
base.AddBlueprintFor(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when a <see cref="HitObject"/> has been transferred to another <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hitObject">The hit object which has been assigned to a new drawable.</param>
|
||||||
|
/// <param name="drawableObject">The new drawable that is representing the hit object.</param>
|
||||||
protected virtual void TransferBlueprintFor(HitObject hitObject, DrawableHitObject drawableObject)
|
protected virtual void TransferBlueprintFor(HitObject hitObject, DrawableHitObject drawableObject)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -160,6 +152,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
Beatmap.HitObjectAdded -= AddBlueprintFor;
|
Beatmap.HitObjectAdded -= AddBlueprintFor;
|
||||||
Beatmap.HitObjectRemoved -= RemoveBlueprintFor;
|
Beatmap.HitObjectRemoved -= RemoveBlueprintFor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
usageEventBuffer?.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,8 +84,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
if (activeHandle?.IsHeld == true)
|
if (activeHandle?.IsHeld == true)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
activeHandle = rotationHandles.SingleOrDefault(h => h.IsHeld || h.IsHovered);
|
activeHandle = rotationHandles.FirstOrDefault(h => h.IsHeld || h.IsHovered);
|
||||||
activeHandle ??= allDragHandles.SingleOrDefault(h => h.IsHovered);
|
activeHandle ??= allDragHandles.FirstOrDefault(h => h.IsHovered);
|
||||||
|
|
||||||
if (activeHandle != null)
|
if (activeHandle != null)
|
||||||
{
|
{
|
||||||
|
@ -350,5 +350,55 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
=> Enumerable.Empty<MenuItem>();
|
=> Enumerable.Empty<MenuItem>();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Helper Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Given a flip direction, a surrounding quad for all selected objects, and a position,
|
||||||
|
/// will return the flipped position in screen space coordinates.
|
||||||
|
/// </summary>
|
||||||
|
protected static Vector2 GetFlippedPosition(Direction direction, Quad quad, Vector2 position)
|
||||||
|
{
|
||||||
|
var centre = quad.Centre;
|
||||||
|
|
||||||
|
switch (direction)
|
||||||
|
{
|
||||||
|
case Direction.Horizontal:
|
||||||
|
position.X = centre.X - (position.X - centre.X);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Direction.Vertical:
|
||||||
|
position.Y = centre.Y - (position.Y - centre.Y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a quad surrounding the provided points.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="points">The points to calculate a quad for.</param>
|
||||||
|
protected static Quad GetSurroundingQuad(IEnumerable<Vector2> points)
|
||||||
|
{
|
||||||
|
if (!points.Any())
|
||||||
|
return new Quad();
|
||||||
|
|
||||||
|
Vector2 minPosition = new Vector2(float.MaxValue, float.MaxValue);
|
||||||
|
Vector2 maxPosition = new Vector2(float.MinValue, float.MinValue);
|
||||||
|
|
||||||
|
// Go through all hitobjects to make sure they would remain in the bounds of the editor after movement, before any movement is attempted
|
||||||
|
foreach (var p in points)
|
||||||
|
{
|
||||||
|
minPosition = Vector2.ComponentMin(minPosition, p);
|
||||||
|
maxPosition = Vector2.ComponentMax(maxPosition, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 size = maxPosition - minPosition;
|
||||||
|
|
||||||
|
return new Quad(minPosition.X, minPosition.Y, size.X, size.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,125 +0,0 @@
|
|||||||
// 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 JetBrains.Annotations;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Game.Rulesets.Objects;
|
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.UI;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.Edit.Compose
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A queue which processes events from the many <see cref="HitObjectContainer"/>s in a nested <see cref="Playfield"/> hierarchy.
|
|
||||||
/// </summary>
|
|
||||||
internal class HitObjectContainerEventQueue : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Invoked when a <see cref="HitObject"/> becomes used by a <see cref="DrawableHitObject"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// If the ruleset uses pooled objects, this represents the time when the <see cref="HitObject"/>s become alive.
|
|
||||||
/// </remarks>
|
|
||||||
public event Action<HitObject> HitObjectUsageBegan;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invoked when a <see cref="HitObject"/> becomes unused by a <see cref="DrawableHitObject"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// If the ruleset uses pooled objects, this represents the time when the <see cref="HitObject"/>s become dead.
|
|
||||||
/// </remarks>
|
|
||||||
public event Action<HitObject> HitObjectUsageFinished;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invoked when a <see cref="HitObject"/> has been transferred to another <see cref="DrawableHitObject"/>.
|
|
||||||
/// </summary>
|
|
||||||
public event Action<HitObject, DrawableHitObject> HitObjectUsageTransferred;
|
|
||||||
|
|
||||||
private readonly Playfield playfield;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new <see cref="HitObjectContainerEventQueue"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="playfield">The most top-level <see cref="Playfield"/>.</param>
|
|
||||||
public HitObjectContainerEventQueue([NotNull] Playfield playfield)
|
|
||||||
{
|
|
||||||
this.playfield = playfield;
|
|
||||||
|
|
||||||
playfield.HitObjectUsageBegan += onHitObjectUsageBegan;
|
|
||||||
playfield.HitObjectUsageFinished += onHitObjectUsageFinished;
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Dictionary<HitObject, EventType> pendingEvents = new Dictionary<HitObject, EventType>();
|
|
||||||
|
|
||||||
private void onHitObjectUsageBegan(HitObject hitObject) => updateEvent(hitObject, EventType.Began);
|
|
||||||
|
|
||||||
private void onHitObjectUsageFinished(HitObject hitObject) => updateEvent(hitObject, EventType.Finished);
|
|
||||||
|
|
||||||
private void updateEvent(HitObject hitObject, EventType newEvent)
|
|
||||||
{
|
|
||||||
if (!pendingEvents.TryGetValue(hitObject, out EventType existingEvent))
|
|
||||||
{
|
|
||||||
pendingEvents[hitObject] = newEvent;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (existingEvent, newEvent)
|
|
||||||
{
|
|
||||||
case (EventType.Transferred, EventType.Finished):
|
|
||||||
pendingEvents[hitObject] = EventType.Finished;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (EventType.Began, EventType.Finished):
|
|
||||||
case (EventType.Finished, EventType.Began):
|
|
||||||
pendingEvents[hitObject] = EventType.Transferred;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException($"Unexpected event update ({existingEvent} => {newEvent}).");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Update()
|
|
||||||
{
|
|
||||||
base.Update();
|
|
||||||
|
|
||||||
foreach (var (hitObject, e) in pendingEvents)
|
|
||||||
{
|
|
||||||
switch (e)
|
|
||||||
{
|
|
||||||
case EventType.Began:
|
|
||||||
HitObjectUsageBegan?.Invoke(hitObject);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EventType.Transferred:
|
|
||||||
HitObjectUsageTransferred?.Invoke(hitObject, playfield.AllHitObjects.Single(d => d.HitObject == hitObject));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EventType.Finished:
|
|
||||||
HitObjectUsageFinished?.Invoke(hitObject);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pendingEvents.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
|
||||||
{
|
|
||||||
base.Dispose(isDisposing);
|
|
||||||
|
|
||||||
playfield.HitObjectUsageBegan -= onHitObjectUsageBegan;
|
|
||||||
playfield.HitObjectUsageFinished -= onHitObjectUsageFinished;
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum EventType
|
|
||||||
{
|
|
||||||
Began,
|
|
||||||
Finished,
|
|
||||||
Transferred
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
83
osu.Game/Screens/Edit/Compose/HitObjectUsageEventBuffer.cs
Normal file
83
osu.Game/Screens/Edit/Compose/HitObjectUsageEventBuffer.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// 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 JetBrains.Annotations;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Edit.Compose
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Buffers events from the many <see cref="HitObjectContainer"/>s in a nested <see cref="Playfield"/> hierarchy
|
||||||
|
/// to ensure correct ordering of events.
|
||||||
|
/// </summary>
|
||||||
|
internal class HitObjectUsageEventBuffer : IDisposable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when a <see cref="HitObject"/> becomes used by a <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If the ruleset uses pooled objects, this represents the time when the <see cref="HitObject"/>s become alive.
|
||||||
|
/// </remarks>
|
||||||
|
public event Action<HitObject> HitObjectUsageBegan;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when a <see cref="HitObject"/> becomes unused by a <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If the ruleset uses pooled objects, this represents the time when the <see cref="HitObject"/>s become dead.
|
||||||
|
/// </remarks>
|
||||||
|
public event Action<HitObject> HitObjectUsageFinished;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when a <see cref="HitObject"/> has been transferred to another <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
public event Action<HitObject, DrawableHitObject> HitObjectUsageTransferred;
|
||||||
|
|
||||||
|
private readonly Playfield playfield;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="HitObjectUsageEventBuffer"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="playfield">The most top-level <see cref="Playfield"/>.</param>
|
||||||
|
public HitObjectUsageEventBuffer([NotNull] Playfield playfield)
|
||||||
|
{
|
||||||
|
this.playfield = playfield;
|
||||||
|
|
||||||
|
playfield.HitObjectUsageBegan += onHitObjectUsageBegan;
|
||||||
|
playfield.HitObjectUsageFinished += onHitObjectUsageFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly List<HitObject> usageFinishedHitObjects = new List<HitObject>();
|
||||||
|
|
||||||
|
private void onHitObjectUsageBegan(HitObject hitObject)
|
||||||
|
{
|
||||||
|
if (usageFinishedHitObjects.Remove(hitObject))
|
||||||
|
HitObjectUsageTransferred?.Invoke(hitObject, playfield.AllHitObjects.Single(d => d.HitObject == hitObject));
|
||||||
|
else
|
||||||
|
HitObjectUsageBegan?.Invoke(hitObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onHitObjectUsageFinished(HitObject hitObject) => usageFinishedHitObjects.Add(hitObject);
|
||||||
|
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
foreach (var hitObject in usageFinishedHitObjects)
|
||||||
|
HitObjectUsageFinished?.Invoke(hitObject);
|
||||||
|
usageFinishedHitObjects.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (playfield != null)
|
||||||
|
{
|
||||||
|
playfield.HitObjectUsageBegan -= onHitObjectUsageBegan;
|
||||||
|
playfield.HitObjectUsageFinished -= onHitObjectUsageFinished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -635,6 +635,9 @@ namespace osu.Game.Screens.Edit
|
|||||||
case EditorScreenMode.Verify:
|
case EditorScreenMode.Verify:
|
||||||
currentScreen = new VerifyScreen();
|
currentScreen = new VerifyScreen();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException("Editor menu bar switched to an unsupported mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadComponentAsync(currentScreen, newScreen =>
|
LoadComponentAsync(currentScreen, newScreen =>
|
||||||
|
@ -37,6 +37,7 @@ namespace osu.Game.Screens.Edit.Verify
|
|||||||
|
|
||||||
private IBeatmapVerifier rulesetVerifier;
|
private IBeatmapVerifier rulesetVerifier;
|
||||||
private BeatmapVerifier generalVerifier;
|
private BeatmapVerifier generalVerifier;
|
||||||
|
private BeatmapVerifierContext context;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OverlayColourProvider colours)
|
private void load(OverlayColourProvider colours)
|
||||||
@ -44,6 +45,9 @@ namespace osu.Game.Screens.Edit.Verify
|
|||||||
generalVerifier = new BeatmapVerifier();
|
generalVerifier = new BeatmapVerifier();
|
||||||
rulesetVerifier = beatmap.BeatmapInfo.Ruleset?.CreateInstance()?.CreateBeatmapVerifier();
|
rulesetVerifier = beatmap.BeatmapInfo.Ruleset?.CreateInstance()?.CreateBeatmapVerifier();
|
||||||
|
|
||||||
|
context = new BeatmapVerifierContext(beatmap, workingBeatmap.Value, verify.InterpretedDifficulty.Value);
|
||||||
|
verify.InterpretedDifficulty.BindValueChanged(difficulty => context.InterpretedDifficulty = difficulty.NewValue);
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
@ -91,10 +95,10 @@ namespace osu.Game.Screens.Edit.Verify
|
|||||||
|
|
||||||
private void refresh()
|
private void refresh()
|
||||||
{
|
{
|
||||||
var issues = generalVerifier.Run(beatmap, workingBeatmap.Value);
|
var issues = generalVerifier.Run(context);
|
||||||
|
|
||||||
if (rulesetVerifier != null)
|
if (rulesetVerifier != null)
|
||||||
issues = issues.Concat(rulesetVerifier.Run(beatmap, workingBeatmap.Value));
|
issues = issues.Concat(rulesetVerifier.Run(context));
|
||||||
|
|
||||||
issues = filter(issues);
|
issues = filter(issues);
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
difficultyIconContainer.Child = new DifficultyIcon(beatmap.Value, ruleset.Value, requiredMods) { Size = new Vector2(32) };
|
difficultyIconContainer.Child = new DifficultyIcon(beatmap.Value, ruleset.Value, requiredMods) { Size = new Vector2(32) };
|
||||||
|
|
||||||
beatmapText.Clear();
|
beatmapText.Clear();
|
||||||
beatmapText.AddLink(Item.Beatmap.ToString(), LinkAction.OpenBeatmap, Item.Beatmap.Value.OnlineBeatmapID.ToString());
|
beatmapText.AddLink(Item.Beatmap.Value.ToRomanisableString(), LinkAction.OpenBeatmap, Item.Beatmap.Value.OnlineBeatmapID.ToString());
|
||||||
|
|
||||||
authorText.Clear();
|
authorText.Clear();
|
||||||
|
|
||||||
|
@ -150,7 +150,11 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
protected void StartPlay()
|
protected void StartPlay()
|
||||||
{
|
{
|
||||||
sampleStart?.Play();
|
sampleStart?.Play();
|
||||||
ParentScreen?.Push(CreateGameplayScreen());
|
|
||||||
|
// fallback is to allow this class to operate when there is no parent OnlineScreen (testing purposes).
|
||||||
|
var targetScreen = (Screen)ParentScreen ?? this;
|
||||||
|
|
||||||
|
targetScreen.Push(CreateGameplayScreen());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -27,6 +27,7 @@ using osu.Game.Screens.OnlinePlay.Match.Components;
|
|||||||
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
|
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
|
||||||
using osu.Game.Screens.OnlinePlay.Multiplayer.Participants;
|
using osu.Game.Screens.OnlinePlay.Multiplayer.Participants;
|
||||||
using osu.Game.Screens.OnlinePlay.Multiplayer.Spectate;
|
using osu.Game.Screens.OnlinePlay.Multiplayer.Spectate;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Screens.Play.HUD;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -452,7 +453,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
|||||||
return new MultiSpectatorScreen(userIds);
|
return new MultiSpectatorScreen(userIds);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return new MultiplayerPlayer(SelectedItem.Value, userIds);
|
return new PlayerLoader(() => new MultiplayerPlayer(SelectedItem.Value, userIds));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ using osu.Game.Online.Rooms;
|
|||||||
using osu.Game.Screens.OnlinePlay.Components;
|
using osu.Game.Screens.OnlinePlay.Components;
|
||||||
using osu.Game.Screens.OnlinePlay.Match;
|
using osu.Game.Screens.OnlinePlay.Match;
|
||||||
using osu.Game.Screens.OnlinePlay.Match.Components;
|
using osu.Game.Screens.OnlinePlay.Match.Components;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Screens.Play.HUD;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -271,9 +272,9 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
|||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Screen CreateGameplayScreen() => new PlaylistsPlayer(SelectedItem.Value)
|
protected override Screen CreateGameplayScreen() => new PlayerLoader(() => new PlaylistsPlayer(SelectedItem.Value)
|
||||||
{
|
{
|
||||||
Exited = () => leaderboard.RefreshScores()
|
Exited = () => leaderboard.RefreshScores()
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -14,6 +15,7 @@ using osu.Game.Graphics.Sprites;
|
|||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Screens.Play.HUD;
|
||||||
|
using osu.Game.Screens.Ranking.Expanded;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play
|
namespace osu.Game.Screens.Play
|
||||||
@ -25,7 +27,7 @@ namespace osu.Game.Screens.Play
|
|||||||
{
|
{
|
||||||
private readonly WorkingBeatmap beatmap;
|
private readonly WorkingBeatmap beatmap;
|
||||||
private readonly Bindable<IReadOnlyList<Mod>> mods;
|
private readonly Bindable<IReadOnlyList<Mod>> mods;
|
||||||
private readonly Drawable facade;
|
private readonly Drawable logoFacade;
|
||||||
private LoadingSpinner loading;
|
private LoadingSpinner loading;
|
||||||
|
|
||||||
public IBindable<IReadOnlyList<Mod>> Mods => mods;
|
public IBindable<IReadOnlyList<Mod>> Mods => mods;
|
||||||
@ -41,19 +43,24 @@ namespace osu.Game.Screens.Play
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public BeatmapMetadataDisplay(WorkingBeatmap beatmap, Bindable<IReadOnlyList<Mod>> mods, Drawable facade)
|
public BeatmapMetadataDisplay(WorkingBeatmap beatmap, Bindable<IReadOnlyList<Mod>> mods, Drawable logoFacade)
|
||||||
{
|
{
|
||||||
this.beatmap = beatmap;
|
this.beatmap = beatmap;
|
||||||
this.facade = facade;
|
this.logoFacade = logoFacade;
|
||||||
|
|
||||||
this.mods = new Bindable<IReadOnlyList<Mod>>();
|
this.mods = new Bindable<IReadOnlyList<Mod>>();
|
||||||
this.mods.BindTo(mods);
|
this.mods.BindTo(mods);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IBindable<StarDifficulty?> starDifficulty;
|
||||||
|
|
||||||
|
private FillFlowContainer versionFlow;
|
||||||
|
private StarRatingDisplay starRatingDisplay;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load(BeatmapDifficultyCache difficultyCache)
|
||||||
{
|
{
|
||||||
var metadata = beatmap.BeatmapInfo?.Metadata ?? new BeatmapMetadata();
|
var metadata = beatmap.BeatmapInfo.Metadata;
|
||||||
|
|
||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
@ -66,7 +73,7 @@ namespace osu.Game.Screens.Play
|
|||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
facade.With(d =>
|
logoFacade.With(d =>
|
||||||
{
|
{
|
||||||
d.Anchor = Anchor.TopCentre;
|
d.Anchor = Anchor.TopCentre;
|
||||||
d.Origin = Anchor.TopCentre;
|
d.Origin = Anchor.TopCentre;
|
||||||
@ -107,16 +114,30 @@ namespace osu.Game.Screens.Play
|
|||||||
loading = new LoadingLayer(true)
|
loading = new LoadingLayer(true)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new OsuSpriteText
|
versionFlow = new FillFlowContainer
|
||||||
{
|
{
|
||||||
Text = beatmap?.BeatmapInfo?.Version,
|
AutoSizeAxes = Axes.Both,
|
||||||
Font = OsuFont.GetFont(size: 26, italics: true),
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Margin = new MarginPadding
|
Origin = Anchor.TopCentre,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(5f),
|
||||||
|
Margin = new MarginPadding { Bottom = 40 },
|
||||||
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
Bottom = 40
|
new OsuSpriteText
|
||||||
},
|
{
|
||||||
|
Text = beatmap?.BeatmapInfo?.Version,
|
||||||
|
Font = OsuFont.GetFont(size: 26, italics: true),
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
},
|
||||||
|
starRatingDisplay = new StarRatingDisplay(default)
|
||||||
|
{
|
||||||
|
Alpha = 0f,
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
new GridContainer
|
new GridContainer
|
||||||
{
|
{
|
||||||
@ -159,9 +180,38 @@ namespace osu.Game.Screens.Play
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
starDifficulty = difficultyCache.GetBindableDifficulty(beatmap.BeatmapInfo);
|
||||||
|
|
||||||
Loading = true;
|
Loading = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
if (starDifficulty.Value != null)
|
||||||
|
{
|
||||||
|
starRatingDisplay.Current.Value = starDifficulty.Value.Value;
|
||||||
|
starRatingDisplay.Show();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
starRatingDisplay.Hide();
|
||||||
|
|
||||||
|
starDifficulty.ValueChanged += d =>
|
||||||
|
{
|
||||||
|
Debug.Assert(d.NewValue != null);
|
||||||
|
|
||||||
|
starRatingDisplay.Current.Value = d.NewValue.Value;
|
||||||
|
|
||||||
|
versionFlow.AutoSizeDuration = 300;
|
||||||
|
versionFlow.AutoSizeEasing = Easing.OutQuint;
|
||||||
|
|
||||||
|
starRatingDisplay.FadeIn(300, Easing.InQuint);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class MetadataLineLabel : OsuSpriteText
|
private class MetadataLineLabel : OsuSpriteText
|
||||||
{
|
{
|
||||||
public MetadataLineLabel(string text)
|
public MetadataLineLabel(string text)
|
||||||
|
@ -2,23 +2,13 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play.HUD
|
namespace osu.Game.Screens.Play.HUD
|
||||||
{
|
{
|
||||||
public class DefaultAccuracyCounter : GameplayAccuracyCounter, ISkinnableComponent
|
public class DefaultAccuracyCounter : GameplayAccuracyCounter, ISkinnableDrawable
|
||||||
{
|
{
|
||||||
private readonly Vector2 offset = new Vector2(-20, 5);
|
|
||||||
|
|
||||||
public DefaultAccuracyCounter()
|
|
||||||
{
|
|
||||||
Origin = Anchor.TopRight;
|
|
||||||
Anchor = Anchor.TopRight;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private HUDOverlay hud { get; set; }
|
private HUDOverlay hud { get; set; }
|
||||||
|
|
||||||
@ -27,17 +17,5 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
{
|
{
|
||||||
Colour = colours.BlueLighter;
|
Colour = colours.BlueLighter;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
|
||||||
{
|
|
||||||
base.Update();
|
|
||||||
|
|
||||||
if (hud?.ScoreCounter.Drawable is DefaultScoreCounter score)
|
|
||||||
{
|
|
||||||
// for now align with the score counter. eventually this will be user customisable.
|
|
||||||
Anchor = Anchor.TopLeft;
|
|
||||||
Position = Parent.ToLocalSpace(score.ScreenSpaceDrawQuad.TopLeft) + offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,14 +9,11 @@ using osu.Game.Graphics.Sprites;
|
|||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play.HUD
|
namespace osu.Game.Screens.Play.HUD
|
||||||
{
|
{
|
||||||
public class DefaultComboCounter : RollingCounter<int>, ISkinnableComponent
|
public class DefaultComboCounter : RollingCounter<int>, ISkinnableDrawable
|
||||||
{
|
{
|
||||||
private readonly Vector2 offset = new Vector2(20, 5);
|
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private HUDOverlay hud { get; set; }
|
private HUDOverlay hud { get; set; }
|
||||||
|
|
||||||
@ -32,17 +29,6 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
Current.BindTo(scoreProcessor.Combo);
|
Current.BindTo(scoreProcessor.Combo);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
|
||||||
{
|
|
||||||
base.Update();
|
|
||||||
|
|
||||||
if (hud?.ScoreCounter.Drawable is DefaultScoreCounter score)
|
|
||||||
{
|
|
||||||
// for now align with the score counter. eventually this will be user customisable.
|
|
||||||
Position = Parent.ToLocalSpace(score.ScreenSpaceDrawQuad.TopRight) + offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override string FormatCount(int count)
|
protected override string FormatCount(int count)
|
||||||
{
|
{
|
||||||
return $@"{count}x";
|
return $@"{count}x";
|
||||||
|
@ -17,7 +17,7 @@ using osu.Game.Skinning;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.Play.HUD
|
namespace osu.Game.Screens.Play.HUD
|
||||||
{
|
{
|
||||||
public class DefaultHealthDisplay : HealthDisplay, IHasAccentColour, ISkinnableComponent
|
public class DefaultHealthDisplay : HealthDisplay, IHasAccentColour, ISkinnableDrawable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The base opacity of the glow.
|
/// The base opacity of the glow.
|
||||||
|
@ -8,7 +8,7 @@ using osu.Game.Skinning;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.Play.HUD
|
namespace osu.Game.Screens.Play.HUD
|
||||||
{
|
{
|
||||||
public class DefaultScoreCounter : GameplayScoreCounter, ISkinnableComponent
|
public class DefaultScoreCounter : GameplayScoreCounter, ISkinnableDrawable
|
||||||
{
|
{
|
||||||
public DefaultScoreCounter()
|
public DefaultScoreCounter()
|
||||||
: base(6)
|
: base(6)
|
||||||
@ -24,12 +24,6 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
Colour = colours.BlueLighter;
|
Colour = colours.BlueLighter;
|
||||||
|
|
||||||
// todo: check if default once health display is skinnable
|
|
||||||
hud?.ShowHealthbar.BindValueChanged(healthBar =>
|
|
||||||
{
|
|
||||||
this.MoveToY(healthBar.NewValue ? 30 : 0, HUDOverlay.FADE_DURATION, HUDOverlay.FADE_EASING);
|
|
||||||
}, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,13 +13,12 @@ using osu.Framework.Graphics.Sprites;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Skinning;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
||||||
{
|
{
|
||||||
public class BarHitErrorMeter : HitErrorMeter, ISkinnableComponent
|
public class BarHitErrorMeter : HitErrorMeter
|
||||||
{
|
{
|
||||||
private readonly Anchor alignment;
|
private readonly Anchor alignment;
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Uses the 'x' symbol and has a pop-out effect while rolling over.
|
/// Uses the 'x' symbol and has a pop-out effect while rolling over.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class LegacyComboCounter : CompositeDrawable, ISkinnableComponent
|
public class LegacyComboCounter : CompositeDrawable, ISkinnableDrawable
|
||||||
{
|
{
|
||||||
public Bindable<int> Current { get; } = new BindableInt { MinValue = 0, };
|
public Bindable<int> Current { get; } = new BindableInt { MinValue = 0, };
|
||||||
|
|
||||||
@ -84,13 +84,13 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
{
|
{
|
||||||
InternalChildren = new[]
|
InternalChildren = new[]
|
||||||
{
|
{
|
||||||
popOutCount = new LegacySpriteText(skin, LegacyFont.Combo)
|
popOutCount = new LegacySpriteText(LegacyFont.Combo)
|
||||||
{
|
{
|
||||||
Alpha = 0,
|
Alpha = 0,
|
||||||
Margin = new MarginPadding(0.05f),
|
Margin = new MarginPadding(0.05f),
|
||||||
Blending = BlendingParameters.Additive,
|
Blending = BlendingParameters.Additive,
|
||||||
},
|
},
|
||||||
displayedCountSpriteText = new LegacySpriteText(skin, LegacyFont.Combo)
|
displayedCountSpriteText = new LegacySpriteText(LegacyFont.Combo)
|
||||||
{
|
{
|
||||||
Alpha = 0,
|
Alpha = 0,
|
||||||
},
|
},
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
// 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.Skinning;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play.HUD
|
|
||||||
{
|
|
||||||
public class SkinnableAccuracyCounter : SkinnableDrawable
|
|
||||||
{
|
|
||||||
public SkinnableAccuracyCounter()
|
|
||||||
: base(new HUDSkinComponent(HUDSkinComponents.AccuracyCounter), _ => new DefaultAccuracyCounter())
|
|
||||||
{
|
|
||||||
CentreComponent = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user