mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 07:42:57 +08:00
Merge branch 'master' into diffcalc-rework
This commit is contained in:
commit
a6437c005c
@ -42,6 +42,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
public virtual bool CanBePlated => false;
|
||||
|
||||
public virtual bool StaysOnPlate => CanBePlated;
|
||||
|
||||
protected DrawableCatchHitObject(CatchHitObject hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
|
@ -13,6 +13,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
private Pulp pulp;
|
||||
|
||||
public override bool StaysOnPlate => false;
|
||||
|
||||
public DrawableDroplet(Droplet h)
|
||||
: base(h)
|
||||
{
|
||||
|
@ -124,6 +124,9 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
X = X + Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH
|
||||
});
|
||||
}
|
||||
|
||||
if (NestedHitObjects.LastOrDefault() is IHasComboInformation lastNested)
|
||||
lastNested.LastInCombo = LastInCombo;
|
||||
}
|
||||
|
||||
public double EndTime => StartTime + this.SpanCount() * Curve.Distance / Velocity;
|
||||
|
@ -48,6 +48,16 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
public void OnJudgement(DrawableCatchHitObject fruit, Judgement judgement)
|
||||
{
|
||||
void runAfterLoaded(Action action)
|
||||
{
|
||||
// this is required to make this run after the last caught fruit runs UpdateState at least once.
|
||||
// TODO: find a better alternative
|
||||
if (lastPlateableFruit.IsLoaded)
|
||||
action();
|
||||
else
|
||||
lastPlateableFruit.OnLoadComplete = _ => action();
|
||||
}
|
||||
|
||||
if (judgement.IsHit && fruit.CanBePlated)
|
||||
{
|
||||
var caughtFruit = (DrawableCatchHitObject)GetVisualRepresentation?.Invoke(fruit.HitObject);
|
||||
@ -63,21 +73,17 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
caughtFruit.LifetimeEnd = double.MaxValue;
|
||||
|
||||
MovableCatcher.Add(caughtFruit);
|
||||
|
||||
lastPlateableFruit = caughtFruit;
|
||||
|
||||
if (!fruit.StaysOnPlate)
|
||||
runAfterLoaded(() => MovableCatcher.Explode(caughtFruit));
|
||||
|
||||
}
|
||||
|
||||
if (fruit.HitObject.LastInCombo)
|
||||
{
|
||||
if (judgement.IsHit)
|
||||
{
|
||||
// this is required to make this run after the last caught fruit runs UpdateState at least once.
|
||||
// TODO: find a better alternative
|
||||
if (lastPlateableFruit.IsLoaded)
|
||||
MovableCatcher.Explode();
|
||||
else
|
||||
lastPlateableFruit.OnLoadComplete = _ => { MovableCatcher.Explode(); };
|
||||
}
|
||||
runAfterLoaded(() => MovableCatcher.Explode());
|
||||
else
|
||||
MovableCatcher.Drop();
|
||||
}
|
||||
@ -378,28 +384,31 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
var fruit = caughtFruit.ToArray();
|
||||
|
||||
foreach (var f in fruit)
|
||||
Explode(f);
|
||||
}
|
||||
|
||||
public void Explode(DrawableHitObject fruit)
|
||||
{
|
||||
var originalX = fruit.X * Scale.X;
|
||||
|
||||
if (ExplodingFruitTarget != null)
|
||||
{
|
||||
var originalX = f.X * Scale.X;
|
||||
fruit.Anchor = Anchor.TopLeft;
|
||||
fruit.Position = caughtFruit.ToSpaceOfOtherDrawable(fruit.DrawPosition, ExplodingFruitTarget);
|
||||
|
||||
if (ExplodingFruitTarget != null)
|
||||
{
|
||||
f.Anchor = Anchor.TopLeft;
|
||||
f.Position = caughtFruit.ToSpaceOfOtherDrawable(f.DrawPosition, ExplodingFruitTarget);
|
||||
caughtFruit.Remove(fruit);
|
||||
|
||||
caughtFruit.Remove(f);
|
||||
|
||||
ExplodingFruitTarget.Add(f);
|
||||
}
|
||||
|
||||
f.MoveToY(f.Y - 50, 250, Easing.OutSine)
|
||||
.Then()
|
||||
.MoveToY(f.Y + 50, 500, Easing.InSine);
|
||||
|
||||
f.MoveToX(f.X + originalX * 6, 1000);
|
||||
f.FadeOut(750);
|
||||
|
||||
f.Expire();
|
||||
ExplodingFruitTarget.Add(fruit);
|
||||
}
|
||||
|
||||
fruit.MoveToY(fruit.Y - 50, 250, Easing.OutSine)
|
||||
.Then()
|
||||
.MoveToY(fruit.Y + 50, 500, Easing.InSine);
|
||||
|
||||
fruit.MoveToX(fruit.X + originalX * 6, 1000);
|
||||
fruit.FadeOut(750);
|
||||
|
||||
fruit.Expire();
|
||||
}
|
||||
|
||||
private class CatcherSprite : Sprite
|
||||
|
@ -58,6 +58,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
|
||||
public override Pattern Generate()
|
||||
{
|
||||
if (TotalColumns == 1)
|
||||
{
|
||||
var pattern = new Pattern();
|
||||
addToPattern(pattern, 0, HitObject.StartTime, endTime);
|
||||
return pattern;
|
||||
}
|
||||
|
||||
if (spanCount > 1)
|
||||
{
|
||||
if (segmentDuration <= 90)
|
||||
|
@ -77,10 +77,25 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
}
|
||||
else
|
||||
convertType |= PatternType.LowProbability;
|
||||
|
||||
if ((convertType & PatternType.KeepSingle) == 0)
|
||||
{
|
||||
if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && TotalColumns != 8)
|
||||
convertType |= PatternType.Mirror;
|
||||
else
|
||||
convertType |= PatternType.Gathered;
|
||||
}
|
||||
}
|
||||
|
||||
public override Pattern Generate()
|
||||
{
|
||||
if (TotalColumns == 1)
|
||||
{
|
||||
var pattern = new Pattern();
|
||||
addToPattern(pattern, 0);
|
||||
return pattern;
|
||||
}
|
||||
|
||||
int lastColumn = PreviousPattern.HitObjects.FirstOrDefault()?.Column ?? 0;
|
||||
|
||||
if ((convertType & PatternType.Reverse) > 0 && PreviousPattern.HitObjects.Any())
|
||||
@ -346,7 +361,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
addToCentre = false;
|
||||
|
||||
if ((convertType & PatternType.ForceNotStack) > 0)
|
||||
return getRandomNoteCount(p2 / 2, p2, (p2 + p3) / 2, p3);
|
||||
return getRandomNoteCount(1 / 2f + p2 / 2, p2, (p2 + p3) / 2, p3);
|
||||
|
||||
switch (TotalColumns)
|
||||
{
|
||||
|
@ -15,6 +15,8 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
internal class HitExplosion : CompositeDrawable
|
||||
{
|
||||
public override bool RemoveWhenNotAlive => true;
|
||||
|
||||
private readonly CircularContainer circle;
|
||||
|
||||
public HitExplosion(DrawableHitObject judgedObject)
|
||||
|
@ -18,6 +18,8 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
/// </summary>
|
||||
internal class HitExplosion : CircularContainer
|
||||
{
|
||||
public override bool RemoveWhenNotAlive => true;
|
||||
|
||||
public readonly DrawableHitObject JudgedObject;
|
||||
|
||||
private readonly Box innerFill;
|
||||
@ -66,7 +68,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
this.ScaleTo(3f, 1000, Easing.OutQuint);
|
||||
this.FadeOut(500);
|
||||
|
||||
Expire();
|
||||
Expire(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -14,6 +14,8 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
{
|
||||
public class KiaiHitExplosion : CircularContainer
|
||||
{
|
||||
public override bool RemoveWhenNotAlive => true;
|
||||
|
||||
public readonly DrawableHitObject JudgedObject;
|
||||
|
||||
private readonly bool isRim;
|
||||
@ -62,7 +64,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
this.ScaleTo(new Vector2(1, 3f), 500, Easing.OutQuint);
|
||||
this.FadeOut(250);
|
||||
|
||||
Expire();
|
||||
Expire(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Overlays.Volume;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual
|
||||
@ -17,13 +18,21 @@ namespace osu.Game.Tests.Visual
|
||||
{
|
||||
VolumeMeter meter;
|
||||
MuteButton mute;
|
||||
Add(meter = new VolumeMeter("MASTER", 125, Color4.Blue));
|
||||
Add(meter = new VolumeMeter("MASTER", 125, Color4.Blue) { Position = new Vector2(10) });
|
||||
AddSliderStep("master volume", 0, 10, 0, i => meter.Bindable.Value = i * 0.1);
|
||||
|
||||
Add(new VolumeMeter("BIG", 250, Color4.Red)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Position = new Vector2(10),
|
||||
});
|
||||
|
||||
Add(mute = new MuteButton
|
||||
{
|
||||
Margin = new MarginPadding { Top = 200 }
|
||||
});
|
||||
|
||||
AddSliderStep("master volume", 0, 10, 0, i => meter.Bindable.Value = i * 0.1);
|
||||
AddToggleStep("mute", b => mute.Current.Value = b);
|
||||
}
|
||||
}
|
||||
|
@ -181,24 +181,6 @@ namespace osu.Game.Database
|
||||
}
|
||||
}
|
||||
|
||||
public void Migrate()
|
||||
{
|
||||
try
|
||||
{
|
||||
Database.Migrate();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new MigrationFailedException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MigrationFailedException : Exception
|
||||
{
|
||||
public MigrationFailedException(Exception exception)
|
||||
: base("sqlite-net migration failed", exception)
|
||||
{
|
||||
}
|
||||
public void Migrate() => Database.Migrate();
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ namespace osu.Game.Graphics.Containers
|
||||
|
||||
/// <summary>
|
||||
/// Whether mouse input should be blocked screen-wide while this overlay is visible.
|
||||
/// Performing mouse actions outside of the valid extents will hide the overlay but pass the events through.
|
||||
/// Performing mouse actions outside of the valid extents will hide the overlay.
|
||||
/// </summary>
|
||||
public virtual bool BlockScreenWideMouse => BlockPassThroughMouse;
|
||||
|
||||
|
@ -149,7 +149,7 @@ namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = $"{SetInfo.Metadata.Source}",
|
||||
Text = SetInfo.Metadata.Source,
|
||||
TextSize = 14,
|
||||
Shadow = false,
|
||||
Colour = colours.Gray5,
|
||||
|
@ -160,7 +160,7 @@ namespace osu.Game.Overlays.Direct
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = $"from {SetInfo.Metadata.Source}",
|
||||
Text = SetInfo.Metadata.Source,
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
TextSize = 14,
|
||||
|
@ -66,34 +66,6 @@ namespace osu.Game.Overlays
|
||||
AlwaysPresent = true;
|
||||
}
|
||||
|
||||
private Vector2 dragStart;
|
||||
|
||||
protected override bool OnDragStart(InputState state)
|
||||
{
|
||||
base.OnDragStart(state);
|
||||
dragStart = state.Mouse.Position;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool OnDrag(InputState state)
|
||||
{
|
||||
if (base.OnDrag(state)) return true;
|
||||
|
||||
Vector2 change = state.Mouse.Position - dragStart;
|
||||
|
||||
// Diminish the drag distance as we go further to simulate "rubber band" feeling.
|
||||
change *= change.Length <= 0 ? 0 : (float)Math.Pow(change.Length, 0.7f) / change.Length;
|
||||
|
||||
dragContainer.MoveTo(change);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool OnDragEnd(InputState state)
|
||||
{
|
||||
dragContainer.MoveTo(Vector2.Zero, 800, Easing.OutElastic);
|
||||
return base.OnDragEnd(state);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(BindableBeatmap beatmap, BeatmapManager beatmaps, OsuColour colours, LocalisationEngine localisation)
|
||||
{
|
||||
@ -103,7 +75,7 @@ namespace osu.Game.Overlays
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
dragContainer = new Container
|
||||
dragContainer = new DragContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@ -470,5 +442,36 @@ namespace osu.Game.Overlays
|
||||
sprite.Texture = beatmap?.Background ?? textures.Get(@"Backgrounds/bg4");
|
||||
}
|
||||
}
|
||||
|
||||
private class DragContainer : Container
|
||||
{
|
||||
private Vector2 dragStart;
|
||||
|
||||
protected override bool OnDragStart(InputState state)
|
||||
{
|
||||
base.OnDragStart(state);
|
||||
dragStart = state.Mouse.Position;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool OnDrag(InputState state)
|
||||
{
|
||||
if (base.OnDrag(state)) return true;
|
||||
|
||||
Vector2 change = state.Mouse.Position - dragStart;
|
||||
|
||||
// Diminish the drag distance as we go further to simulate "rubber band" feeling.
|
||||
change *= change.Length <= 0 ? 0 : (float)Math.Pow(change.Length, 0.7f) / change.Length;
|
||||
|
||||
this.MoveTo(change);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool OnDragEnd(InputState state)
|
||||
{
|
||||
this.MoveTo(Vector2.Zero, 800, Easing.OutElastic);
|
||||
return base.OnDragEnd(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ namespace osu.Game.Overlays.Volume
|
||||
public class VolumeMeter : Container, IKeyBindingHandler<GlobalAction>
|
||||
{
|
||||
private CircularProgress volumeCircle;
|
||||
private CircularProgress volumeCircleGlow;
|
||||
|
||||
public BindableDouble Bindable { get; } = new BindableDouble { MinValue = 0, MaxValue = 1 };
|
||||
private readonly float circleSize;
|
||||
private readonly Color4 meterColour;
|
||||
@ -44,90 +46,143 @@ namespace osu.Game.Overlays.Volume
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
Add(new Container
|
||||
{
|
||||
Size = new Vector2(120, 20),
|
||||
CornerRadius = 10,
|
||||
Masking = true,
|
||||
Margin = new MarginPadding { Left = circleSize + 10 },
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colours.Gray1,
|
||||
Alpha = 0.9f,
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Font = "Exo2.0-Bold",
|
||||
Text = name
|
||||
}
|
||||
}
|
||||
});
|
||||
Color4 backgroundColour = colours.Gray1;
|
||||
|
||||
CircularProgress bgProgress;
|
||||
|
||||
Add(new CircularContainer
|
||||
const float progress_start_radius = 0.75f;
|
||||
const float progress_size = 0.03f;
|
||||
const float progress_end_radius = progress_start_radius + progress_size;
|
||||
|
||||
const float blur_amount = 5;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Masking = true,
|
||||
Size = new Vector2(circleSize),
|
||||
Children = new Drawable[]
|
||||
new Container
|
||||
{
|
||||
new Box
|
||||
Size = new Vector2(circleSize),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colours.Gray1,
|
||||
Alpha = 0.9f,
|
||||
},
|
||||
bgProgress = new CircularProgress
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
InnerRadius = 0.05f,
|
||||
Rotation = 180,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Colour = colours.Gray2,
|
||||
Size = new Vector2(0.8f)
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Size = new Vector2(0.8f),
|
||||
Padding = new MarginPadding(-Blur.KernelSize(5)),
|
||||
Rotation = 180,
|
||||
Child = (volumeCircle = new CircularProgress
|
||||
new BufferedContainer
|
||||
{
|
||||
Alpha = 0.9f,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
InnerRadius = 0.05f,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Circle
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = backgroundColour,
|
||||
},
|
||||
new CircularContainer
|
||||
{
|
||||
Masking = true,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Size = new Vector2(progress_end_radius),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
bgProgress = new CircularProgress
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Rotation = 180,
|
||||
Colour = backgroundColour,
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Name = "Progress under covers for smoothing",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Rotation = 180,
|
||||
Child = volumeCircle = new CircularProgress
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
new Circle
|
||||
{
|
||||
Name = "Inner Cover",
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = backgroundColour,
|
||||
Size = new Vector2(progress_start_radius),
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Name = "Progress overlay for glow",
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Size = new Vector2(progress_start_radius + progress_size / 1.5f),
|
||||
Rotation = 180,
|
||||
Padding = new MarginPadding(-Blur.KernelSize(blur_amount)),
|
||||
Child = (volumeCircleGlow = new CircularProgress
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
InnerRadius = progress_size * 0.8f,
|
||||
}).WithEffect(new GlowEffect
|
||||
{
|
||||
Colour = meterColour,
|
||||
BlurSigma = new Vector2(blur_amount),
|
||||
Strength = 5,
|
||||
PadExtent = true
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
maxGlow = (text = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Font = "Venera",
|
||||
TextSize = 0.16f * circleSize
|
||||
}).WithEffect(new GlowEffect
|
||||
{
|
||||
Colour = meterColour,
|
||||
Strength = 2,
|
||||
PadExtent = true
|
||||
}),
|
||||
},
|
||||
maxGlow = (text = new OsuSpriteText
|
||||
Colour = Color4.Transparent,
|
||||
PadExtent = true,
|
||||
})
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Size = new Vector2(120, 20),
|
||||
CornerRadius = 10,
|
||||
Masking = true,
|
||||
Margin = new MarginPadding { Left = circleSize + 10 },
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Font = "Venera",
|
||||
TextSize = 0.16f * circleSize
|
||||
}).WithEffect(new GlowEffect
|
||||
{
|
||||
Colour = Color4.Transparent,
|
||||
PadExtent = true,
|
||||
})
|
||||
new Box
|
||||
{
|
||||
Alpha = 0.9f,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = backgroundColour,
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Font = "Exo2.0-Bold",
|
||||
Text = name
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Bindable.ValueChanged += newVolume => { this.TransformTo("DisplayVolume", newVolume, 400, Easing.OutQuint); };
|
||||
};
|
||||
Bindable.ValueChanged += newVolume =>
|
||||
{
|
||||
this.TransformTo("DisplayVolume",
|
||||
newVolume,
|
||||
400,
|
||||
Easing.OutQuint);
|
||||
};
|
||||
bgProgress.Current.Value = 0.75f;
|
||||
}
|
||||
|
||||
@ -158,6 +213,7 @@ namespace osu.Game.Overlays.Volume
|
||||
}
|
||||
|
||||
volumeCircle.Current.Value = displayVolume * 0.75f;
|
||||
volumeCircleGlow.Current.Value = displayVolume * 0.75f;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,8 @@ using osu.Game.Rulesets.Objects;
|
||||
namespace osu.Game.Tests.Beatmaps
|
||||
{
|
||||
[TestFixture]
|
||||
public abstract class BeatmapConversionTest<TConvertValue>
|
||||
public abstract class BeatmapConversionTest<TConvertMapping, TConvertValue>
|
||||
where TConvertMapping : ConvertMapping<TConvertValue>, IEquatable<TConvertMapping>, new()
|
||||
where TConvertValue : IEquatable<TConvertValue>
|
||||
{
|
||||
private const string resource_namespace = "Testing.Beatmaps";
|
||||
@ -59,9 +60,13 @@ namespace osu.Game.Tests.Beatmaps
|
||||
else if (objectCounter >= expectedMapping.Objects.Count)
|
||||
Assert.Fail($"The conversion generated a hitobject, but should not have, for hitobject at time: {ourMapping.StartTime}:\n"
|
||||
+ $"Received: {JsonConvert.SerializeObject(ourMapping.Objects[objectCounter])}\n");
|
||||
else if (!EqualityComparer<TConvertValue>.Default.Equals(expectedMapping.Objects[objectCounter], ourMapping.Objects[objectCounter]))
|
||||
else if (!expectedMapping.Equals(ourMapping))
|
||||
Assert.Fail($"The conversion mapping differed for object at time {expectedMapping.StartTime}:\n"
|
||||
+ $"Expected {JsonConvert.SerializeObject(expectedMapping)}\n"
|
||||
+ $"Received: {JsonConvert.SerializeObject(ourMapping)}\n");
|
||||
else if (!expectedMapping.Objects[objectCounter].Equals(ourMapping.Objects[objectCounter]))
|
||||
{
|
||||
Assert.Fail($"The conversion generated differing hitobjects for object at time: {expectedMapping.StartTime}\n"
|
||||
Assert.Fail($"The conversion generated differing hitobjects for object at time: {expectedMapping.StartTime}:\n"
|
||||
+ $"Expected: {JsonConvert.SerializeObject(expectedMapping.Objects[objectCounter])}\n"
|
||||
+ $"Received: {JsonConvert.SerializeObject(ourMapping.Objects[objectCounter])}\n");
|
||||
}
|
||||
@ -84,19 +89,22 @@ namespace osu.Game.Tests.Beatmaps
|
||||
beatmap.BeatmapInfo.Ruleset = beatmap.BeatmapInfo.RulesetID == rulesetInstance.RulesetInfo.ID ? rulesetInstance.RulesetInfo : new RulesetInfo();
|
||||
|
||||
var result = new ConvertResult();
|
||||
|
||||
var converter = rulesetInstance.CreateBeatmapConverter(beatmap);
|
||||
|
||||
converter.ObjectConverted += (orig, converted) =>
|
||||
{
|
||||
converted.ForEach(h => h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty));
|
||||
|
||||
var mapping = new ConvertMapping { StartTime = orig.StartTime };
|
||||
var mapping = CreateConvertMapping();
|
||||
mapping.StartTime = orig.StartTime;
|
||||
|
||||
foreach (var obj in converted)
|
||||
mapping.Objects.AddRange(CreateConvertValue(obj));
|
||||
result.Mappings.Add(mapping);
|
||||
};
|
||||
|
||||
converter.Convert();
|
||||
IBeatmap convertedBeatmap = converter.Convert();
|
||||
rulesetInstance.CreateBeatmapProcessor(convertedBeatmap)?.PostProcess();
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -128,21 +136,54 @@ namespace osu.Game.Tests.Beatmaps
|
||||
return Assembly.LoadFrom(Path.Combine(localPath, $"{ResourceAssembly}.dll")).GetManifestResourceStream($@"{ResourceAssembly}.Resources.{name}");
|
||||
}
|
||||
|
||||
protected abstract IEnumerable<TConvertValue> CreateConvertValue(HitObject hitObject);
|
||||
protected abstract Ruleset CreateRuleset();
|
||||
/// <summary>
|
||||
/// Creates the conversion mapping for a <see cref="HitObject"/>. A conversion mapping stores important information about the conversion process.
|
||||
/// This is generated _after_ the <see cref="HitObject"/> has been converted.
|
||||
/// <para>
|
||||
/// This should be used to validate the integrity of the conversion process after a conversion has occurred.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
protected virtual TConvertMapping CreateConvertMapping() => new TConvertMapping();
|
||||
|
||||
private class ConvertMapping
|
||||
{
|
||||
[JsonProperty]
|
||||
public double StartTime;
|
||||
[JsonProperty]
|
||||
public List<TConvertValue> Objects = new List<TConvertValue>();
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates the conversion value for a <see cref="HitObject"/>. A conversion value stores information about the converted <see cref="HitObject"/>.
|
||||
/// <para>
|
||||
/// This should be used to validate the integrity of the converted <see cref="HitObject"/>.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="hitObject">The converted <see cref="HitObject"/>.</param>
|
||||
protected abstract IEnumerable<TConvertValue> CreateConvertValue(HitObject hitObject);
|
||||
|
||||
/// <summary>
|
||||
/// Creates the <see cref="Ruleset"/> applicable to this <see cref="BeatmapConversionTest{TConvertMapping,TConvertValue}"/>.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected abstract Ruleset CreateRuleset();
|
||||
|
||||
private class ConvertResult
|
||||
{
|
||||
[JsonProperty]
|
||||
public List<ConvertMapping> Mappings = new List<ConvertMapping>();
|
||||
public List<TConvertMapping> Mappings = new List<TConvertMapping>();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class BeatmapConversionTest<TConvertValue> : BeatmapConversionTest<ConvertMapping<TConvertValue>, TConvertValue>
|
||||
where TConvertValue : IEquatable<TConvertValue>
|
||||
{
|
||||
}
|
||||
|
||||
public class ConvertMapping<TConvertValue> : IEquatable<ConvertMapping<TConvertValue>>
|
||||
where TConvertValue : IEquatable<TConvertValue>
|
||||
{
|
||||
[JsonProperty]
|
||||
public double StartTime;
|
||||
|
||||
[JsonIgnore]
|
||||
public List<TConvertValue> Objects = new List<TConvertValue>();
|
||||
|
||||
[JsonProperty("Objects")]
|
||||
private List<TConvertValue> setObjects { set => Objects = value; }
|
||||
|
||||
public virtual bool Equals(ConvertMapping<TConvertValue> other) => StartTime.Equals(other?.StartTime);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user