mirror of
https://github.com/ppy/osu.git
synced 2025-01-26 16:12:54 +08:00
Merge remote-tracking branch 'upstream/master' into peppy-fix-repeat-arrow-interpolation
This commit is contained in:
commit
51506efd1a
@ -7,6 +7,7 @@ using osu.Framework.Extensions.Color4Extensions;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||||
{
|
{
|
||||||
@ -20,27 +21,26 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
|||||||
{
|
{
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
Masking = true;
|
Child = new SkinnableDrawable("Play/osu/followpoint", _ => new Container
|
||||||
AutoSizeAxes = Axes.Both;
|
|
||||||
CornerRadius = width / 2;
|
|
||||||
EdgeEffect = new EdgeEffectParameters
|
|
||||||
{
|
{
|
||||||
Type = EdgeEffectType.Glow,
|
Masking = true,
|
||||||
Colour = Color4.White.Opacity(0.2f),
|
AutoSizeAxes = Axes.Both,
|
||||||
Radius = 4,
|
CornerRadius = width / 2,
|
||||||
};
|
EdgeEffect = new EdgeEffectParameters
|
||||||
|
{
|
||||||
Children = new Drawable[]
|
Type = EdgeEffectType.Glow,
|
||||||
{
|
Colour = Color4.White.Opacity(0.2f),
|
||||||
new Box
|
Radius = 4,
|
||||||
|
},
|
||||||
|
Child = new Box
|
||||||
{
|
{
|
||||||
Size = new Vector2(width),
|
Size = new Vector2(width),
|
||||||
Blending = BlendingMode.Additive,
|
Blending = BlendingMode.Additive,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Alpha = 0.5f,
|
Alpha = 0.5f,
|
||||||
},
|
}
|
||||||
};
|
}, restrictSize: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
|||||||
|
|
||||||
Vector2 distanceVector = endPosition - startPosition;
|
Vector2 distanceVector = endPosition - startPosition;
|
||||||
int distance = (int)distanceVector.Length;
|
int distance = (int)distanceVector.Length;
|
||||||
float rotation = (float)Math.Atan2(distanceVector.Y, distanceVector.X);
|
float rotation = (float)(Math.Atan2(distanceVector.Y, distanceVector.X) * (180 / Math.PI));
|
||||||
double duration = endTime - startTime;
|
double duration = endTime - startTime;
|
||||||
|
|
||||||
for (int d = (int)(PointDistance * 1.5); d < distance - PointDistance; d += PointDistance)
|
for (int d = (int)(PointDistance * 1.5); d < distance - PointDistance; d += PointDistance)
|
||||||
|
@ -10,6 +10,7 @@ using OpenTK;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||||
{
|
{
|
||||||
@ -33,11 +34,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteIcon
|
new SkinnableDrawable("Play/osu/reversearrow", _ => new SpriteIcon
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Icon = FontAwesome.fa_chevron_right
|
Icon = FontAwesome.fa_chevron_right
|
||||||
}
|
}, restrictSize: false)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@ using OpenTK.Graphics;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||||
{
|
{
|
||||||
@ -22,23 +24,27 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick)
|
public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick)
|
||||||
{
|
{
|
||||||
Size = new Vector2(16) * sliderTick.Scale;
|
Size = new Vector2(16) * sliderTick.Scale;
|
||||||
|
|
||||||
Masking = true;
|
|
||||||
CornerRadius = Size.X / 2;
|
|
||||||
|
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
BorderThickness = 2;
|
|
||||||
BorderColour = Color4.White;
|
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new SkinnableDrawable("Play/osu/sliderscorepoint", _ => new Container
|
||||||
{
|
{
|
||||||
|
Masking = true,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = AccentColour,
|
Origin = Anchor.Centre,
|
||||||
Alpha = 0.3f,
|
CornerRadius = Size.X / 2,
|
||||||
}
|
|
||||||
|
BorderThickness = 2,
|
||||||
|
BorderColour = Color4.White,
|
||||||
|
|
||||||
|
Child = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = AccentColour,
|
||||||
|
Alpha = 0.3f,
|
||||||
|
}
|
||||||
|
}, restrictSize: false)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ using osu.Framework.Input.States;
|
|||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||||
{
|
{
|
||||||
@ -18,6 +19,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
private const float width = 128;
|
private const float width = 128;
|
||||||
|
|
||||||
private Color4 accentColour = Color4.Black;
|
private Color4 accentColour = Color4.Black;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The colour that is used for the slider ball.
|
/// The colour that is used for the slider ball.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -27,14 +29,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
accentColour = value;
|
accentColour = value;
|
||||||
if (ball != null)
|
if (drawableBall != null)
|
||||||
ball.Colour = value;
|
drawableBall.Colour = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Slider slider;
|
private readonly Slider slider;
|
||||||
public readonly Box FollowCircle;
|
public readonly Drawable FollowCircle;
|
||||||
private readonly Box ball;
|
private Drawable drawableBall;
|
||||||
|
|
||||||
public SliderBall(Slider slider)
|
public SliderBall(Slider slider)
|
||||||
{
|
{
|
||||||
@ -43,19 +45,30 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
Blending = BlendingMode.Additive;
|
Blending = BlendingMode.Additive;
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
BorderThickness = 10;
|
|
||||||
BorderColour = Color4.Orange;
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
FollowCircle = new Box
|
FollowCircle = new Container
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Colour = Color4.Orange,
|
|
||||||
Width = width,
|
Width = width,
|
||||||
Height = width,
|
Height = width,
|
||||||
Alpha = 0,
|
Alpha = 0,
|
||||||
|
Child = new SkinnableDrawable("Play/osu/sliderfollowcircle", _ => new CircularContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
BorderThickness = 5,
|
||||||
|
BorderColour = Color4.Orange,
|
||||||
|
Blending = BlendingMode.Additive,
|
||||||
|
Child = new Box
|
||||||
|
{
|
||||||
|
Colour = Color4.Orange,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0.2f,
|
||||||
|
}
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
new CircularContainer
|
new CircularContainer
|
||||||
{
|
{
|
||||||
@ -63,18 +76,26 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
BorderThickness = 10,
|
|
||||||
BorderColour = Color4.White,
|
|
||||||
Alpha = 1,
|
Alpha = 1,
|
||||||
Children = new[]
|
Child = new Container
|
||||||
{
|
{
|
||||||
ball = new Box
|
Width = width,
|
||||||
|
Height = width,
|
||||||
|
// TODO: support skin filename animation (sliderb0, sliderb1...)
|
||||||
|
Child = new SkinnableDrawable("Play/osu/sliderb", _ => new CircularContainer
|
||||||
{
|
{
|
||||||
Colour = AccentColour,
|
Masking = true,
|
||||||
Alpha = 0.4f,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Width = width,
|
BorderThickness = 10,
|
||||||
Height = width,
|
BorderColour = Color4.White,
|
||||||
},
|
Alpha = 1,
|
||||||
|
Child = drawableBall = new Box
|
||||||
|
{
|
||||||
|
Colour = AccentColour,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0.4f,
|
||||||
|
}
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -111,6 +132,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
}
|
}
|
||||||
|
|
||||||
private bool tracking;
|
private bool tracking;
|
||||||
|
|
||||||
public bool Tracking
|
public bool Tracking
|
||||||
{
|
{
|
||||||
get { return tracking; }
|
get { return tracking; }
|
||||||
@ -121,7 +143,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
tracking = value;
|
tracking = value;
|
||||||
|
|
||||||
FollowCircle.ScaleTo(tracking ? 2f : 1, 300, Easing.OutQuint);
|
FollowCircle.ScaleTo(tracking ? 2f : 1, 300, Easing.OutQuint);
|
||||||
FollowCircle.FadeTo(tracking ? 0.2f : 0, 300, Easing.OutQuint);
|
FollowCircle.FadeTo(tracking ? 1f : 0, 300, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,7 +530,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
public new List<DrawableCarouselItem> Items => base.Items;
|
public new List<DrawableCarouselItem> Items => base.Items;
|
||||||
|
|
||||||
public bool PendingFilterTask => FilterTask != null;
|
public bool PendingFilterTask => PendingFilter != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,8 @@ namespace osu.Game.Tests.Visual
|
|||||||
public new BeatmapCarousel Carousel => base.Carousel;
|
public new BeatmapCarousel Carousel => base.Carousel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TestSongSelect songSelect;
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
{
|
{
|
||||||
factory.ResetDatabase();
|
factory.ResetDatabase();
|
||||||
@ -63,11 +65,14 @@ namespace osu.Game.Tests.Visual
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
TestSongSelect songSelect = null;
|
|
||||||
|
|
||||||
factory = new DatabaseContextFactory(LocalStorage);
|
factory = new DatabaseContextFactory(LocalStorage);
|
||||||
factory.ResetDatabase();
|
factory.ResetDatabase();
|
||||||
|
|
||||||
|
using (var usage = factory.Get())
|
||||||
|
usage.Migrate();
|
||||||
|
|
||||||
|
factory.ResetDatabase();
|
||||||
|
|
||||||
using (var usage = factory.Get())
|
using (var usage = factory.Get())
|
||||||
usage.Migrate();
|
usage.Migrate();
|
||||||
|
|
||||||
@ -77,42 +82,35 @@ namespace osu.Game.Tests.Visual
|
|||||||
DefaultBeatmap = defaultBeatmap = Beatmap.Default
|
DefaultBeatmap = defaultBeatmap = Beatmap.Default
|
||||||
});
|
});
|
||||||
|
|
||||||
void loadNewSongSelect(bool deleteMaps = false) => AddStep("reload song select", () =>
|
Beatmap.SetDefault();
|
||||||
{
|
}
|
||||||
if (deleteMaps)
|
|
||||||
{
|
|
||||||
manager.Delete(manager.GetAllUsableBeatmapSets());
|
|
||||||
Beatmap.SetDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (songSelect != null)
|
[SetUp]
|
||||||
{
|
public virtual void SetUp()
|
||||||
Remove(songSelect);
|
{
|
||||||
songSelect.Dispose();
|
manager?.Delete(manager.GetAllUsableBeatmapSets());
|
||||||
}
|
Child = songSelect = new TestSongSelect();
|
||||||
|
}
|
||||||
Add(songSelect = new TestSongSelect());
|
|
||||||
});
|
|
||||||
|
|
||||||
loadNewSongSelect(true);
|
|
||||||
|
|
||||||
AddWaitStep(3);
|
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestDummy()
|
||||||
|
{
|
||||||
AddAssert("dummy selected", () => songSelect.CurrentBeatmap == defaultBeatmap);
|
AddAssert("dummy selected", () => songSelect.CurrentBeatmap == defaultBeatmap);
|
||||||
|
|
||||||
AddAssert("dummy shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap == defaultBeatmap);
|
AddAssert("dummy shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap == defaultBeatmap);
|
||||||
|
|
||||||
AddStep("import test maps", () =>
|
addManyTestMaps();
|
||||||
{
|
|
||||||
for (int i = 0; i < 100; i += 10)
|
|
||||||
manager.Import(createTestBeatmapSet(i));
|
|
||||||
});
|
|
||||||
|
|
||||||
AddWaitStep(3);
|
AddWaitStep(3);
|
||||||
|
|
||||||
AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap);
|
AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap);
|
||||||
|
}
|
||||||
|
|
||||||
loadNewSongSelect();
|
[Test]
|
||||||
|
public void TestSorting()
|
||||||
|
{
|
||||||
|
addManyTestMaps();
|
||||||
AddWaitStep(3);
|
AddWaitStep(3);
|
||||||
|
|
||||||
AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap);
|
AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap);
|
||||||
|
|
||||||
AddStep(@"Sort by Artist", delegate { songSelect.FilterControl.Sort = SortMode.Artist; });
|
AddStep(@"Sort by Artist", delegate { songSelect.FilterControl.Sort = SortMode.Artist; });
|
||||||
@ -121,55 +119,84 @@ namespace osu.Game.Tests.Visual
|
|||||||
AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; });
|
AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; });
|
||||||
}
|
}
|
||||||
|
|
||||||
private BeatmapSetInfo createTestBeatmapSet(int i)
|
[Test]
|
||||||
|
[Ignore("needs fixing")]
|
||||||
|
public void ImportUnderDifferentRuleset()
|
||||||
{
|
{
|
||||||
|
changeRuleset(2);
|
||||||
|
importForRuleset(0);
|
||||||
|
AddUntilStep(() => songSelect.Carousel.SelectedBeatmap == null, "no selection");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ImportUnderCurrentRuleset()
|
||||||
|
{
|
||||||
|
changeRuleset(2);
|
||||||
|
importForRuleset(2);
|
||||||
|
importForRuleset(1);
|
||||||
|
AddUntilStep(() => songSelect.Carousel.SelectedBeatmap.RulesetID == 2, "has selection");
|
||||||
|
|
||||||
|
changeRuleset(1);
|
||||||
|
AddUntilStep(() => songSelect.Carousel.SelectedBeatmap.RulesetID == 1, "has selection");
|
||||||
|
|
||||||
|
changeRuleset(0);
|
||||||
|
AddUntilStep(() => songSelect.Carousel.SelectedBeatmap == null, "no selection");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void importForRuleset(int id) => AddStep($"import test map for ruleset {id}", () => manager.Import(createTestBeatmapSet(getImportId(), rulesets.AvailableRulesets.Where(r => r.ID == id).ToArray())));
|
||||||
|
|
||||||
|
private static int importId;
|
||||||
|
private int getImportId() => ++importId;
|
||||||
|
|
||||||
|
private void changeRuleset(int id) => AddStep($"change ruleset to {id}", () => Ruleset.Value = rulesets.AvailableRulesets.First(r => r.ID == id));
|
||||||
|
|
||||||
|
private void addManyTestMaps()
|
||||||
|
{
|
||||||
|
AddStep("import test maps", () =>
|
||||||
|
{
|
||||||
|
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray();
|
||||||
|
|
||||||
|
for (int i = 0; i < 100; i += 10)
|
||||||
|
manager.Import(createTestBeatmapSet(i, usableRulesets));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private BeatmapSetInfo createTestBeatmapSet(int setId, RulesetInfo[] rulesets)
|
||||||
|
{
|
||||||
|
int j = 0;
|
||||||
|
RulesetInfo getRuleset() => rulesets[j++ % rulesets.Length];
|
||||||
|
|
||||||
|
var beatmaps = new List<BeatmapInfo>();
|
||||||
|
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
int beatmapId = setId * 10 + i;
|
||||||
|
|
||||||
|
beatmaps.Add(new BeatmapInfo
|
||||||
|
{
|
||||||
|
Ruleset = getRuleset(),
|
||||||
|
OnlineBeatmapID = beatmapId,
|
||||||
|
Path = "normal.osu",
|
||||||
|
Version = $"{beatmapId}",
|
||||||
|
BaseDifficulty = new BeatmapDifficulty
|
||||||
|
{
|
||||||
|
OverallDifficulty = 3.5f,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return new BeatmapSetInfo
|
return new BeatmapSetInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapSetID = 1234 + i,
|
OnlineBeatmapSetID = setId,
|
||||||
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
|
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
|
||||||
Metadata = new BeatmapMetadata
|
Metadata = new BeatmapMetadata
|
||||||
{
|
{
|
||||||
// Create random metadata, then we can check if sorting works based on these
|
// Create random metadata, then we can check if sorting works based on these
|
||||||
Artist = "MONACA " + RNG.Next(0, 9),
|
Artist = "Some Artist " + RNG.Next(0, 9),
|
||||||
Title = "Black Song " + RNG.Next(0, 9),
|
Title = $"Some Song (set id {setId})",
|
||||||
AuthorString = "Some Guy " + RNG.Next(0, 9),
|
AuthorString = "Some Guy " + RNG.Next(0, 9),
|
||||||
},
|
},
|
||||||
Beatmaps = new List<BeatmapInfo>(new[]
|
Beatmaps = beatmaps
|
||||||
{
|
|
||||||
new BeatmapInfo
|
|
||||||
{
|
|
||||||
OnlineBeatmapID = 1234 + i,
|
|
||||||
Ruleset = rulesets.AvailableRulesets.First(),
|
|
||||||
Path = "normal.osu",
|
|
||||||
Version = "Normal",
|
|
||||||
BaseDifficulty = new BeatmapDifficulty
|
|
||||||
{
|
|
||||||
OverallDifficulty = 3.5f,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new BeatmapInfo
|
|
||||||
{
|
|
||||||
OnlineBeatmapID = 1235 + i,
|
|
||||||
Ruleset = rulesets.AvailableRulesets.First(),
|
|
||||||
Path = "hard.osu",
|
|
||||||
Version = "Hard",
|
|
||||||
BaseDifficulty = new BeatmapDifficulty
|
|
||||||
{
|
|
||||||
OverallDifficulty = 5,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new BeatmapInfo
|
|
||||||
{
|
|
||||||
OnlineBeatmapID = 1236 + i,
|
|
||||||
Ruleset = rulesets.AvailableRulesets.First(),
|
|
||||||
Path = "insane.osu",
|
|
||||||
Version = "Insane",
|
|
||||||
BaseDifficulty = new BeatmapDifficulty
|
|
||||||
{
|
|
||||||
OverallDifficulty = 7,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,6 +134,8 @@ namespace osu.Game.Beatmaps
|
|||||||
return converted;
|
return converted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ToString() => BeatmapInfo.ToString();
|
||||||
|
|
||||||
public bool BackgroundLoaded => background.IsResultAvailable;
|
public bool BackgroundLoaded => background.IsResultAvailable;
|
||||||
public Texture Background => background.Value.Result;
|
public Texture Background => background.Value.Result;
|
||||||
public async Task<Texture> GetBackgroundAsync() => await background.Value;
|
public async Task<Texture> GetBackgroundAsync() => await background.Value;
|
||||||
|
@ -197,7 +197,13 @@ namespace osu.Game
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(beatmap.Beatmaps.First());
|
var databasedSet = BeatmapManager.QueryBeatmapSet(s => s.OnlineBeatmapSetID == beatmap.OnlineBeatmapSetID);
|
||||||
|
|
||||||
|
// Use first beatmap available for current ruleset, else switch ruleset.
|
||||||
|
var first = databasedSet.Beatmaps.FirstOrDefault(b => b.Ruleset == ruleset.Value) ?? databasedSet.Beatmaps.First();
|
||||||
|
|
||||||
|
ruleset.Value = first.Ruleset;
|
||||||
|
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(first);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (currentScreen)
|
switch (currentScreen)
|
||||||
|
@ -14,6 +14,7 @@ namespace osu.Game.Overlays.Direct
|
|||||||
{
|
{
|
||||||
public class DownloadButton : OsuAnimatedButton
|
public class DownloadButton : OsuAnimatedButton
|
||||||
{
|
{
|
||||||
|
private readonly BeatmapSetInfo beatmapSet;
|
||||||
private readonly SpriteIcon icon;
|
private readonly SpriteIcon icon;
|
||||||
private readonly SpriteIcon checkmark;
|
private readonly SpriteIcon checkmark;
|
||||||
private readonly BeatmapSetDownloader downloader;
|
private readonly BeatmapSetDownloader downloader;
|
||||||
@ -21,11 +22,13 @@ namespace osu.Game.Overlays.Direct
|
|||||||
|
|
||||||
private OsuColour colours;
|
private OsuColour colours;
|
||||||
|
|
||||||
public DownloadButton(BeatmapSetInfo set, bool noVideo = false)
|
public DownloadButton(BeatmapSetInfo beatmapSet, bool noVideo = false)
|
||||||
{
|
{
|
||||||
|
this.beatmapSet = beatmapSet;
|
||||||
|
|
||||||
AddRange(new Drawable[]
|
AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
downloader = new BeatmapSetDownloader(set, noVideo),
|
downloader = new BeatmapSetDownloader(beatmapSet, noVideo),
|
||||||
background = new Box
|
background = new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
@ -47,26 +50,6 @@ namespace osu.Game.Overlays.Direct
|
|||||||
Icon = FontAwesome.fa_check,
|
Icon = FontAwesome.fa_check,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Action = () =>
|
|
||||||
{
|
|
||||||
if (downloader.DownloadState == BeatmapSetDownloader.DownloadStatus.Downloading)
|
|
||||||
{
|
|
||||||
// todo: replace with ShakeContainer after https://github.com/ppy/osu/pull/2909 is merged.
|
|
||||||
Content.MoveToX(-5, 50, Easing.OutSine).Then()
|
|
||||||
.MoveToX(5, 100, Easing.InOutSine).Then()
|
|
||||||
.MoveToX(-5, 100, Easing.InOutSine).Then()
|
|
||||||
.MoveToX(0, 50, Easing.InSine);
|
|
||||||
}
|
|
||||||
else if (downloader.DownloadState == BeatmapSetDownloader.DownloadStatus.Downloaded)
|
|
||||||
{
|
|
||||||
// TODO: Jump to song select with this set when the capability is implemented
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
downloader.Download();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -77,9 +60,29 @@ namespace osu.Game.Overlays.Direct
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(permitNulls: true)]
|
[BackgroundDependencyLoader(permitNulls: true)]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours, OsuGame game)
|
||||||
{
|
{
|
||||||
this.colours = colours;
|
this.colours = colours;
|
||||||
|
|
||||||
|
Action = () =>
|
||||||
|
{
|
||||||
|
switch (downloader.DownloadState.Value)
|
||||||
|
{
|
||||||
|
case BeatmapSetDownloader.DownloadStatus.Downloading:
|
||||||
|
// todo: replace with ShakeContainer after https://github.com/ppy/osu/pull/2909 is merged.
|
||||||
|
Content.MoveToX(-5, 50, Easing.OutSine).Then()
|
||||||
|
.MoveToX(5, 100, Easing.InOutSine).Then()
|
||||||
|
.MoveToX(-5, 100, Easing.InOutSine).Then()
|
||||||
|
.MoveToX(0, 50, Easing.InSine);
|
||||||
|
break;
|
||||||
|
case BeatmapSetDownloader.DownloadStatus.Downloaded:
|
||||||
|
game.PresentBeatmap(beatmapSet);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
downloader.Download();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateState(BeatmapSetDownloader.DownloadStatus state)
|
private void updateState(BeatmapSetDownloader.DownloadStatus state)
|
||||||
|
@ -25,5 +25,7 @@ namespace osu.Game.Rulesets
|
|||||||
public virtual Ruleset CreateInstance() => (Ruleset)Activator.CreateInstance(Type.GetType(InstantiationInfo), this);
|
public virtual Ruleset CreateInstance() => (Ruleset)Activator.CreateInstance(Type.GetType(InstantiationInfo), this);
|
||||||
|
|
||||||
public bool Equals(RulesetInfo other) => other != null && ID == other.ID && Available == other.Available && Name == other.Name && InstantiationInfo == other.InstantiationInfo;
|
public bool Equals(RulesetInfo other) => other != null && ID == other.ID && Available == other.Available && Name == other.Name && InstantiationInfo == other.InstantiationInfo;
|
||||||
|
|
||||||
|
public override string ToString() => $"{Name} ({ShortName}) ID: {ID}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -330,13 +330,13 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
private FilterCriteria activeCriteria = new FilterCriteria();
|
private FilterCriteria activeCriteria = new FilterCriteria();
|
||||||
|
|
||||||
protected ScheduledDelegate FilterTask;
|
protected ScheduledDelegate PendingFilter;
|
||||||
|
|
||||||
public bool AllowSelection = true;
|
public bool AllowSelection = true;
|
||||||
|
|
||||||
public void FlushPendingFilterOperations()
|
public void FlushPendingFilterOperations()
|
||||||
{
|
{
|
||||||
if (FilterTask?.Completed == false)
|
if (PendingFilter?.Completed == false)
|
||||||
{
|
{
|
||||||
applyActiveCriteria(false, false);
|
applyActiveCriteria(false, false);
|
||||||
Update();
|
Update();
|
||||||
@ -357,18 +357,18 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
void perform()
|
void perform()
|
||||||
{
|
{
|
||||||
FilterTask = null;
|
PendingFilter = null;
|
||||||
|
|
||||||
root.Filter(activeCriteria);
|
root.Filter(activeCriteria);
|
||||||
itemsCache.Invalidate();
|
itemsCache.Invalidate();
|
||||||
if (scroll) scrollPositionCache.Invalidate();
|
if (scroll) scrollPositionCache.Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
FilterTask?.Cancel();
|
PendingFilter?.Cancel();
|
||||||
FilterTask = null;
|
PendingFilter = null;
|
||||||
|
|
||||||
if (debounce)
|
if (debounce)
|
||||||
FilterTask = Scheduler.AddDelayed(perform, 250);
|
PendingFilter = Scheduler.AddDelayed(perform, 250);
|
||||||
else
|
else
|
||||||
perform();
|
perform();
|
||||||
}
|
}
|
||||||
|
@ -182,7 +182,7 @@ namespace osu.Game.Screens.Select
|
|||||||
showConverted.ValueChanged += val => updateCriteria();
|
showConverted.ValueChanged += val => updateCriteria();
|
||||||
|
|
||||||
ruleset.BindTo(parentRuleset);
|
ruleset.BindTo(parentRuleset);
|
||||||
ruleset.BindValueChanged(val => updateCriteria(), true);
|
ruleset.BindValueChanged(_ => updateCriteria(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateCriteria() => FilterChanged?.Invoke(CreateCriteria());
|
private void updateCriteria() => FilterChanged?.Invoke(CreateCriteria());
|
||||||
|
@ -12,6 +12,7 @@ using osu.Framework.Audio.Track;
|
|||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Input.EventArgs;
|
using osu.Framework.Input.EventArgs;
|
||||||
using osu.Framework.Input.States;
|
using osu.Framework.Input.States;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
@ -199,10 +200,6 @@ namespace osu.Game.Screens.Select
|
|||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuColour colours)
|
private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuColour colours)
|
||||||
{
|
{
|
||||||
// manual binding to parent ruleset to allow for delayed load in the incoming direction.
|
|
||||||
base.Ruleset.ValueChanged += r => updateSelectedBeatmap(beatmapNoDebounce);
|
|
||||||
Ruleset.ValueChanged += r => base.Ruleset.Value = r;
|
|
||||||
|
|
||||||
if (Footer != null)
|
if (Footer != null)
|
||||||
{
|
{
|
||||||
Footer.AddButton(@"random", colours.Green, triggerRandom, Key.F2);
|
Footer.AddButton(@"random", colours.Green, triggerRandom, Key.F2);
|
||||||
@ -225,15 +222,6 @@ namespace osu.Game.Screens.Select
|
|||||||
sampleChangeBeatmap = audio.Sample.Get(@"SongSelect/select-expand");
|
sampleChangeBeatmap = audio.Sample.Get(@"SongSelect/select-expand");
|
||||||
|
|
||||||
Carousel.BeatmapSets = this.beatmaps.GetAllUsableBeatmapSetsEnumerable();
|
Carousel.BeatmapSets = this.beatmaps.GetAllUsableBeatmapSetsEnumerable();
|
||||||
|
|
||||||
Beatmap.BindDisabledChanged(disabled => Carousel.AllowSelection = !disabled, true);
|
|
||||||
Beatmap.BindValueChanged(workingBeatmapChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
base.Ruleset.ValueChanged += r => updateSelectedBeatmap(beatmapNoDebounce);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Edit(BeatmapInfo beatmap)
|
public void Edit(BeatmapInfo beatmap)
|
||||||
@ -296,59 +284,86 @@ namespace osu.Game.Screens.Select
|
|||||||
private BeatmapInfo beatmapNoDebounce;
|
private BeatmapInfo beatmapNoDebounce;
|
||||||
private RulesetInfo rulesetNoDebounce;
|
private RulesetInfo rulesetNoDebounce;
|
||||||
|
|
||||||
|
private void updateSelectedBeatmap(BeatmapInfo beatmap)
|
||||||
|
{
|
||||||
|
if (beatmap?.Equals(beatmapNoDebounce) == true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
beatmapNoDebounce = beatmap;
|
||||||
|
performUpdateSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSelectedRuleset(RulesetInfo ruleset)
|
||||||
|
{
|
||||||
|
if (ruleset?.Equals(rulesetNoDebounce) == true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rulesetNoDebounce = ruleset;
|
||||||
|
performUpdateSelected();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// selection has been changed as the result of a user interaction.
|
/// selection has been changed as the result of a user interaction.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void updateSelectedBeatmap(BeatmapInfo beatmap)
|
private void performUpdateSelected()
|
||||||
{
|
{
|
||||||
var ruleset = base.Ruleset.Value;
|
var beatmap = beatmapNoDebounce;
|
||||||
|
var ruleset = rulesetNoDebounce;
|
||||||
|
|
||||||
void performLoad()
|
void run()
|
||||||
{
|
{
|
||||||
|
Logger.Log($"updating selection with beatmap:{beatmap?.ID.ToString() ?? "null"} ruleset:{ruleset?.ID.ToString() ?? "null"}");
|
||||||
|
|
||||||
WorkingBeatmap working = Beatmap.Value;
|
WorkingBeatmap working = Beatmap.Value;
|
||||||
|
|
||||||
bool preview = false;
|
bool preview = false;
|
||||||
|
|
||||||
|
if (ruleset?.Equals(Ruleset.Value) == false)
|
||||||
|
{
|
||||||
|
Logger.Log($"ruleset changed from \"{Ruleset.Value}\" to \"{ruleset}\"");
|
||||||
|
Ruleset.Value = ruleset;
|
||||||
|
|
||||||
|
// force a filter before attempting to change the beatmap.
|
||||||
|
// we may still be in the wrong ruleset as there is a debounce delay on ruleset changes.
|
||||||
|
Carousel.Filter(null, false);
|
||||||
|
|
||||||
|
// Filtering only completes after the carousel runs Update.
|
||||||
|
// If we also have a pending beatmap change we should delay it one frame.
|
||||||
|
selectionChangedDebounce = Schedule(run);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// We may be arriving here due to another component changing the bindable Beatmap.
|
// We may be arriving here due to another component changing the bindable Beatmap.
|
||||||
// In these cases, the other component has already loaded the beatmap, so we don't need to do so again.
|
// In these cases, the other component has already loaded the beatmap, so we don't need to do so again.
|
||||||
if (beatmap?.Equals(Beatmap.Value.BeatmapInfo) != true)
|
if (!Equals(beatmap, Beatmap.Value.BeatmapInfo))
|
||||||
{
|
{
|
||||||
|
Logger.Log($"beatmap changed from \"{Beatmap.Value.BeatmapInfo}\" to \"{beatmap}\"");
|
||||||
|
|
||||||
preview = beatmap?.BeatmapSetInfoID != Beatmap.Value?.BeatmapInfo.BeatmapSetInfoID;
|
preview = beatmap?.BeatmapSetInfoID != Beatmap.Value?.BeatmapInfo.BeatmapSetInfoID;
|
||||||
working = beatmaps.GetWorkingBeatmap(beatmap, Beatmap.Value);
|
working = beatmaps.GetWorkingBeatmap(beatmap, Beatmap.Value);
|
||||||
|
|
||||||
|
if (beatmap != null)
|
||||||
|
{
|
||||||
|
if (beatmap.BeatmapSetInfoID == beatmapNoDebounce?.BeatmapSetInfoID)
|
||||||
|
sampleChangeDifficulty.Play();
|
||||||
|
else
|
||||||
|
sampleChangeBeatmap.Play();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
working.Mods.Value = Enumerable.Empty<Mod>();
|
working.Mods.Value = Enumerable.Empty<Mod>();
|
||||||
|
|
||||||
Beatmap.Value = working;
|
Beatmap.Value = working;
|
||||||
Ruleset.Value = ruleset;
|
|
||||||
|
|
||||||
ensurePlayingSelected(preview);
|
ensurePlayingSelected(preview);
|
||||||
|
|
||||||
UpdateBeatmap(Beatmap.Value);
|
UpdateBeatmap(Beatmap.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (beatmap?.Equals(beatmapNoDebounce) == true && ruleset?.Equals(rulesetNoDebounce) == true)
|
|
||||||
return;
|
|
||||||
|
|
||||||
selectionChangedDebounce?.Cancel();
|
selectionChangedDebounce?.Cancel();
|
||||||
|
|
||||||
beatmapNoDebounce = beatmap;
|
|
||||||
rulesetNoDebounce = ruleset;
|
|
||||||
|
|
||||||
if (beatmap == null)
|
if (beatmap == null)
|
||||||
performLoad();
|
run();
|
||||||
else
|
else
|
||||||
{
|
selectionChangedDebounce = Scheduler.AddDelayed(run, 200);
|
||||||
if (beatmap.BeatmapSetInfoID == beatmapNoDebounce?.BeatmapSetInfoID)
|
|
||||||
sampleChangeDifficulty.Play();
|
|
||||||
else
|
|
||||||
sampleChangeBeatmap.Play();
|
|
||||||
|
|
||||||
if (beatmap == Beatmap.Value.BeatmapInfo)
|
|
||||||
performLoad();
|
|
||||||
else
|
|
||||||
selectionChangedDebounce = Scheduler.AddDelayed(performLoad, 200);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void triggerRandom()
|
private void triggerRandom()
|
||||||
@ -464,6 +479,8 @@ namespace osu.Game.Screens.Select
|
|||||||
/// <param name="beatmap">The working beatmap.</param>
|
/// <param name="beatmap">The working beatmap.</param>
|
||||||
protected virtual void UpdateBeatmap(WorkingBeatmap beatmap)
|
protected virtual void UpdateBeatmap(WorkingBeatmap beatmap)
|
||||||
{
|
{
|
||||||
|
Logger.Log($"working beatmap updated to {beatmap}");
|
||||||
|
|
||||||
if (Background is BackgroundScreenBeatmap backgroundModeBeatmap)
|
if (Background is BackgroundScreenBeatmap backgroundModeBeatmap)
|
||||||
{
|
{
|
||||||
backgroundModeBeatmap.Beatmap = beatmap;
|
backgroundModeBeatmap.Beatmap = beatmap;
|
||||||
@ -495,6 +512,17 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
private void carouselBeatmapsLoaded()
|
private void carouselBeatmapsLoaded()
|
||||||
{
|
{
|
||||||
|
if (rulesetNoDebounce == null)
|
||||||
|
{
|
||||||
|
// manual binding to parent ruleset to allow for delayed load in the incoming direction.
|
||||||
|
rulesetNoDebounce = Ruleset.Value = base.Ruleset.Value;
|
||||||
|
base.Ruleset.ValueChanged += updateSelectedRuleset;
|
||||||
|
Ruleset.ValueChanged += r => base.Ruleset.Value = r;
|
||||||
|
|
||||||
|
Beatmap.BindDisabledChanged(disabled => Carousel.AllowSelection = !disabled, true);
|
||||||
|
Beatmap.BindValueChanged(workingBeatmapChanged);
|
||||||
|
}
|
||||||
|
|
||||||
if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false && Beatmap.Value.BeatmapSetInfo?.Protected == false
|
if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false && Beatmap.Value.BeatmapSetInfo?.Protected == false
|
||||||
&& Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo, false))
|
&& Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo, false))
|
||||||
return;
|
return;
|
||||||
@ -503,7 +531,7 @@ namespace osu.Game.Screens.Select
|
|||||||
{
|
{
|
||||||
// in the case random selection failed, we want to trigger selectionChanged
|
// in the case random selection failed, we want to trigger selectionChanged
|
||||||
// to show the dummy beatmap (we have nothing else to display).
|
// to show the dummy beatmap (we have nothing else to display).
|
||||||
updateSelectedBeatmap(null);
|
performUpdateSelected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user