Merge remote-tracking branch 'origin/master' into direct-list-view

This commit is contained in:
smoogipoo
2018-08-08 15:48:34 +09:00
28 changed files with 579 additions and 179 deletions

View File

@ -27,7 +27,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="System.IO.Packaging" Version="4.5.0" /> <PackageReference Include="System.IO.Packaging" Version="4.5.0" />
<PackageReference Include="ppy.squirrel.windows" Version="1.8.0.3" /> <PackageReference Include="ppy.squirrel.windows" Version="1.8.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.1" />
</ItemGroup> </ItemGroup>

View File

@ -14,24 +14,20 @@ namespace osu.Game.Rulesets.Mania.Tests
/// </summary> /// </summary>
public class ScrollingTestContainer : Container public class ScrollingTestContainer : Container
{ {
private readonly ScrollingDirection direction; [Cached(Type = typeof(IScrollingInfo))]
private readonly TestScrollingInfo scrollingInfo = new TestScrollingInfo();
public ScrollingTestContainer(ScrollingDirection direction) public ScrollingTestContainer(ScrollingDirection direction)
{ {
this.direction = direction; scrollingInfo.Direction.Value = direction;
} }
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) public void Flip() => scrollingInfo.Direction.Value = scrollingInfo.Direction.Value == ScrollingDirection.Up ? ScrollingDirection.Down : ScrollingDirection.Up;
{ }
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.CacheAs<IScrollingInfo>(new ScrollingInfo { Direction = { Value = direction }});
return dependencies;
}
private class ScrollingInfo : IScrollingInfo public class TestScrollingInfo : IScrollingInfo
{ {
public readonly Bindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>(); public readonly Bindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
IBindable<ScrollingDirection> IScrollingInfo.Direction => Direction; IBindable<ScrollingDirection> IScrollingInfo.Direction => Direction;
}
} }
} }

View File

@ -0,0 +1,32 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Game.Rulesets.Mania.Configuration;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Mania.Tests
{
[TestFixture]
public class TestCaseEditor : EditorTestCase
{
private readonly Bindable<ManiaScrollingDirection> direction = new Bindable<ManiaScrollingDirection>();
public TestCaseEditor()
: base(new ManiaRuleset())
{
AddStep("upwards scroll", () => direction.Value = ManiaScrollingDirection.Up);
AddStep("downwards scroll", () => direction.Value = ManiaScrollingDirection.Down);
}
[BackgroundDependencyLoader]
private void load(RulesetConfigCache configCache)
{
var config = (ManiaConfigManager)configCache.GetConfigFor(Ruleset.Value.CreateInstance());
config.BindWith(ManiaSetting.ScrollDirection, direction);
}
}
}

View File

@ -46,15 +46,20 @@ namespace osu.Game.Rulesets.Mania.Tests
Spacing = new Vector2(20), Spacing = new Vector2(20),
Children = new[] Children = new[]
{ {
createNoteDisplay(ScrollingDirection.Down), createNoteDisplay(ScrollingDirection.Down, 1, out var note1),
createNoteDisplay(ScrollingDirection.Up), createNoteDisplay(ScrollingDirection.Up, 2, out var note2),
createHoldNoteDisplay(ScrollingDirection.Down), createHoldNoteDisplay(ScrollingDirection.Down, 1, out var holdNote1),
createHoldNoteDisplay(ScrollingDirection.Up), createHoldNoteDisplay(ScrollingDirection.Up, 2, out var holdNote2),
} }
}; };
AddAssert("note 1 facing downwards", () => verifyAnchors(note1, Anchor.y2));
AddAssert("note 2 facing upwards", () => verifyAnchors(note2, Anchor.y0));
AddAssert("hold note 1 facing downwards", () => verifyAnchors(holdNote1, Anchor.y2));
AddAssert("hold note 2 facing upwards", () => verifyAnchors(holdNote2, Anchor.y0));
} }
private Drawable createNoteDisplay(ScrollingDirection direction) private Drawable createNoteDisplay(ScrollingDirection direction, int identifier, out DrawableNote hitObject)
{ {
var note = new Note { StartTime = 999999999 }; var note = new Note { StartTime = 999999999 };
note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
@ -62,24 +67,24 @@ namespace osu.Game.Rulesets.Mania.Tests
return new ScrollingTestContainer(direction) return new ScrollingTestContainer(direction)
{ {
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Child = new NoteContainer(direction, $"note, scrolling {direction.ToString().ToLowerInvariant()}") Child = new NoteContainer(direction, $"note {identifier}, scrolling {direction.ToString().ToLowerInvariant()}")
{ {
Child = new DrawableNote(note) { AccentColour = Color4.OrangeRed } Child = hitObject = new DrawableNote(note) { AccentColour = Color4.OrangeRed }
} }
}; };
} }
private Drawable createHoldNoteDisplay(ScrollingDirection direction) private Drawable createHoldNoteDisplay(ScrollingDirection direction, int identifier, out DrawableHoldNote hitObject)
{ {
var note = new HoldNote { StartTime = 999999999, Duration = 1000 }; var note = new HoldNote { StartTime = 999999999, Duration = 5000 };
note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
return new ScrollingTestContainer(direction) return new ScrollingTestContainer(direction)
{ {
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Child = new NoteContainer(direction, $"hold note, scrolling {direction.ToString().ToLowerInvariant()}") Child = new NoteContainer(direction, $"hold note {identifier}, scrolling {direction.ToString().ToLowerInvariant()}")
{ {
Child = new DrawableHoldNote(note) Child = hitObject = new DrawableHoldNote(note)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
AccentColour = Color4.OrangeRed, AccentColour = Color4.OrangeRed,
@ -88,6 +93,12 @@ namespace osu.Game.Rulesets.Mania.Tests
}; };
} }
private bool verifyAnchors(DrawableHitObject hitObject, Anchor expectedAnchor)
=> hitObject.Anchor.HasFlag(expectedAnchor) && hitObject.Origin.HasFlag(expectedAnchor);
private bool verifyAnchors(DrawableHoldNote holdNote, Anchor expectedAnchor)
=> verifyAnchors((DrawableHitObject)holdNote, expectedAnchor) && holdNote.NestedHitObjects.All(n => verifyAnchors(n, expectedAnchor));
private class NoteContainer : Container private class NoteContainer : Container
{ {
private readonly Container content; private readonly Container content;

View File

@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -24,6 +25,8 @@ namespace osu.Game.Rulesets.Mania.Tests
private readonly List<ManiaStage> stages = new List<ManiaStage>(); private readonly List<ManiaStage> stages = new List<ManiaStage>();
private FillFlowContainer<ScrollingTestContainer> fill;
public TestCaseStage() public TestCaseStage()
: base(columns) : base(columns)
{ {
@ -32,7 +35,7 @@ namespace osu.Game.Rulesets.Mania.Tests
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
Child = new FillFlowContainer Child = fill = new FillFlowContainer<ScrollingTestContainer>
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
@ -54,8 +57,22 @@ namespace osu.Game.Rulesets.Mania.Tests
AddStep("hold note", createHoldNote); AddStep("hold note", createHoldNote);
AddStep("minor bar line", () => createBarLine(false)); AddStep("minor bar line", () => createBarLine(false));
AddStep("major bar line", () => createBarLine(true)); AddStep("major bar line", () => createBarLine(true));
AddAssert("check note anchors", () => notesInStageAreAnchored(stages[0], Anchor.TopCentre));
AddAssert("check note anchors", () => notesInStageAreAnchored(stages[1], Anchor.BottomCentre));
AddStep("flip direction", () =>
{
foreach (var c in fill.Children)
c.Flip();
});
AddAssert("check note anchors", () => notesInStageAreAnchored(stages[0], Anchor.BottomCentre));
AddAssert("check note anchors", () => notesInStageAreAnchored(stages[1], Anchor.TopCentre));
} }
private bool notesInStageAreAnchored(ManiaStage stage, Anchor anchor) => stage.Columns.SelectMany(c => c.AllHitObjects).All(o => o.Anchor == anchor);
private void createNote() private void createNote()
{ {
foreach (var stage in stages) foreach (var stage in stages)
@ -101,7 +118,7 @@ namespace osu.Game.Rulesets.Mania.Tests
} }
} }
private Drawable createStage(ScrollingDirection direction, ManiaAction action) private ScrollingTestContainer createStage(ScrollingDirection direction, ManiaAction action)
{ {
var specialAction = ManiaAction.Special1; var specialAction = ManiaAction.Special1;

View File

@ -0,0 +1,84 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.UI.Scrolling;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays
{
public class HoldNoteMask : HitObjectMask
{
public new DrawableHoldNote HitObject => (DrawableHoldNote)base.HitObject;
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
private readonly BodyPiece body;
public HoldNoteMask(DrawableHoldNote hold)
: base(hold)
{
InternalChildren = new Drawable[]
{
new HoldNoteNoteMask(hold.Head),
new HoldNoteNoteMask(hold.Tail),
body = new BodyPiece
{
AccentColour = Color4.Transparent
},
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours, IScrollingInfo scrollingInfo)
{
body.BorderColour = colours.Yellow;
direction.BindTo(scrollingInfo.Direction);
}
protected override void Update()
{
base.Update();
Size = HitObject.DrawSize + new Vector2(0, HitObject.Tail.DrawHeight);
Position = Parent.ToLocalSpace(HitObject.ScreenSpaceDrawQuad.TopLeft);
// This is a side-effect of not matching the hitobject's anchors/origins, which is kinda hard to do
// When scrolling upwards our origin is already at the top of the head note (which is the intended location),
// but when scrolling downwards our origin is at the _bottom_ of the tail note (where we need to be at the _top_ of the tail note)
if (direction.Value == ScrollingDirection.Down)
Y -= HitObject.Tail.DrawHeight;
}
private class HoldNoteNoteMask : NoteMask
{
public HoldNoteNoteMask(DrawableNote note)
: base(note)
{
Select();
}
protected override void Update()
{
base.Update();
Anchor = HitObject.Anchor;
Origin = HitObject.Origin;
Position = HitObject.DrawPosition;
}
// Todo: This is temporary, since the note masks don't do anything special yet. In the future they will handle input.
public override bool HandleMouseInput => false;
}
}
}

View File

@ -0,0 +1,39 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Game.Graphics;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays
{
public class NoteMask : HitObjectMask
{
public NoteMask(DrawableNote note)
: base(note)
{
Scale = note.Scale;
CornerRadius = 5;
Masking = true;
AddInternal(new NotePiece());
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Colour = colours.Yellow;
}
protected override void Update()
{
base.Update();
Size = HitObject.DrawSize;
Position = Parent.ToLocalSpace(HitObject.ScreenSpaceDrawQuad.TopLeft);
}
}
}

View File

@ -0,0 +1,17 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.UI;
using System.Collections.Generic;
namespace osu.Game.Rulesets.Mania.Edit
{
public class ManiaEditPlayfield : ManiaPlayfield
{
public ManiaEditPlayfield(List<StageDefinition> stages)
: base(stages)
{
}
}
}

View File

@ -0,0 +1,27 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using OpenTK;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mania.Edit
{
public class ManiaEditRulesetContainer : ManiaRulesetContainer
{
public ManiaEditRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap)
: base(ruleset, beatmap)
{
}
protected override Playfield CreatePlayfield() => new ManiaEditPlayfield(Beatmap.Stages)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
};
protected override Vector2 PlayfieldArea => Vector2.One;
}
}

View File

@ -0,0 +1,56 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI;
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Game.Rulesets.Mania.Configuration;
using osu.Game.Rulesets.Mania.UI;
namespace osu.Game.Rulesets.Mania.Edit
{
public class ManiaHitObjectComposer : HitObjectComposer
{
protected new ManiaConfigManager Config => (ManiaConfigManager)base.Config;
public ManiaHitObjectComposer(Ruleset ruleset)
: base(ruleset)
{
}
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.CacheAs<IScrollingInfo>(new ManiaScrollingInfo(Config));
return dependencies;
}
protected override RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => new ManiaEditRulesetContainer(ruleset, beatmap);
protected override IReadOnlyList<ICompositionTool> CompositionTools => new ICompositionTool[]
{
new HitObjectCompositionTool<Note>("Note"),
new HitObjectCompositionTool<HoldNote>("Hold"),
};
public override HitObjectMask CreateMaskFor(DrawableHitObject hitObject)
{
switch (hitObject)
{
case DrawableNote note:
return new NoteMask(note);
case DrawableHoldNote holdNote:
return new HoldNoteMask(holdNote);
}
return base.CreateMaskFor(hitObject);
}
}
}

View File

@ -19,9 +19,11 @@ using osu.Game.Configuration;
using osu.Game.Overlays.Settings; using osu.Game.Overlays.Settings;
using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Configuration;
using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Configuration; using osu.Game.Rulesets.Mania.Configuration;
using osu.Game.Rulesets.Mania.Difficulty; using osu.Game.Rulesets.Mania.Difficulty;
using osu.Game.Rulesets.Mania.Edit;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Mania namespace osu.Game.Rulesets.Mania
@ -32,6 +34,8 @@ namespace osu.Game.Rulesets.Mania
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap); public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap);
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, Score score) => new ManiaPerformanceCalculator(this, beatmap, score); public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, Score score) => new ManiaPerformanceCalculator(this, beatmap, score);
public override HitObjectComposer CreateHitObjectComposer() => new ManiaHitObjectComposer(this);
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods) public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
{ {
if (mods.HasFlag(LegacyMods.Nightcore)) if (mods.HasFlag(LegacyMods.Nightcore))

View File

@ -21,8 +21,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
public override bool DisplayJudgement => false; public override bool DisplayJudgement => false;
private readonly DrawableNote head; public readonly DrawableNote Head;
private readonly DrawableNote tail; public readonly DrawableNote Tail;
private readonly BodyPiece bodyPiece; private readonly BodyPiece bodyPiece;
@ -57,12 +57,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
HoldStartTime = () => holdStartTime HoldStartTime = () => holdStartTime
}) })
}, },
head = new DrawableHeadNote(this) Head = new DrawableHeadNote(this)
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre Origin = Anchor.TopCentre
}, },
tail = new DrawableTailNote(this) Tail = new DrawableTailNote(this)
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre Origin = Anchor.TopCentre
@ -72,8 +72,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
foreach (var tick in tickContainer) foreach (var tick in tickContainer)
AddNested(tick); AddNested(tick);
AddNested(head); AddNested(Head);
AddNested(tail); AddNested(Tail);
} }
protected override void OnDirectionChanged(ScrollingDirection direction) protected override void OnDirectionChanged(ScrollingDirection direction)
@ -91,15 +91,15 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
base.AccentColour = value; base.AccentColour = value;
bodyPiece.AccentColour = value; bodyPiece.AccentColour = value;
head.AccentColour = value; Head.AccentColour = value;
tail.AccentColour = value; Tail.AccentColour = value;
tickContainer.ForEach(t => t.AccentColour = value); tickContainer.ForEach(t => t.AccentColour = value);
} }
} }
protected override void CheckForJudgements(bool userTriggered, double timeOffset) protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{ {
if (tail.AllJudged) if (Tail.AllJudged)
AddJudgement(new HoldNoteJudgement { Result = HitResult.Perfect }); AddJudgement(new HoldNoteJudgement { Result = HitResult.Perfect });
} }
@ -108,8 +108,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
base.Update(); base.Update();
// Make the body piece not lie under the head note // Make the body piece not lie under the head note
bodyPiece.Y = (Direction.Value == ScrollingDirection.Up ? 1 : -1) * head.Height / 2; bodyPiece.Y = (Direction.Value == ScrollingDirection.Up ? 1 : -1) * Head.Height / 2;
bodyPiece.Height = DrawHeight - head.Height / 2 + tail.Height / 2; bodyPiece.Height = DrawHeight - Head.Height / 2 + Tail.Height / 2;
} }
public bool OnPressed(ManiaAction action) public bool OnPressed(ManiaAction action)
@ -141,7 +141,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
holdStartTime = null; holdStartTime = null;
// If the key has been released too early, the user should not receive full score for the release // If the key has been released too early, the user should not receive full score for the release
if (!tail.IsHit) if (!Tail.IsHit)
hasBroken = true; hasBroken = true;
return true; return true;

View File

@ -8,7 +8,7 @@ using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.UI namespace osu.Game.Rulesets.Mania.UI
{ {
internal class DrawableManiaJudgement : DrawableJudgement public class DrawableManiaJudgement : DrawableJudgement
{ {
public DrawableManiaJudgement(Judgement judgement, DrawableHitObject judgedObject) public DrawableManiaJudgement(Judgement judgement, DrawableHitObject judgedObject)
: base(judgement, judgedObject) : base(judgement, judgedObject)

View File

@ -1,22 +1,20 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Mania.Configuration; using osu.Game.Rulesets.Mania.Configuration;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.UI namespace osu.Game.Rulesets.Mania.UI
{ {
public class ManiaPlayfield : ManiaScrollingPlayfield public class ManiaPlayfield : ManiaScrollingPlayfield
{ {
public List<Column> Columns => stages.SelectMany(x => x.Columns).ToList();
private readonly List<ManiaStage> stages = new List<ManiaStage>(); private readonly List<ManiaStage> stages = new List<ManiaStage>();
public ManiaPlayfield(List<StageDefinition> stageDefinitions) public ManiaPlayfield(List<StageDefinition> stageDefinitions)

View File

@ -4,7 +4,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input; using osu.Framework.Input;
@ -35,8 +34,7 @@ namespace osu.Game.Rulesets.Mania.UI
public IEnumerable<BarLine> BarLines; public IEnumerable<BarLine> BarLines;
private readonly Bindable<ManiaScrollingDirection> configDirection = new Bindable<ManiaScrollingDirection>(); protected new ManiaConfigManager Config => (ManiaConfigManager)base.Config;
private ScrollingInfo scrollingInfo;
public ManiaRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) public ManiaRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap)
: base(ruleset, beatmap) : base(ruleset, beatmap)
@ -73,9 +71,6 @@ namespace osu.Game.Rulesets.Mania.UI
private void load() private void load()
{ {
BarLines.ForEach(Playfield.Add); BarLines.ForEach(Playfield.Add);
((ManiaConfigManager)Config).BindWith(ManiaSetting.ScrollDirection, configDirection);
configDirection.BindValueChanged(d => scrollingInfo.Direction.Value = (ScrollingDirection)d, true);
} }
private DependencyContainer dependencies; private DependencyContainer dependencies;
@ -83,11 +78,14 @@ namespace osu.Game.Rulesets.Mania.UI
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{ {
dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.CacheAs<IScrollingInfo>(scrollingInfo = new ScrollingInfo());
if (dependencies.Get<ManiaScrollingInfo>() == null)
dependencies.CacheAs<IScrollingInfo>(new ManiaScrollingInfo(Config));
return dependencies; return dependencies;
} }
protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages) protected override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
@ -115,11 +113,5 @@ namespace osu.Game.Rulesets.Mania.UI
protected override Vector2 PlayfieldArea => new Vector2(1, 0.8f); protected override Vector2 PlayfieldArea => new Vector2(1, 0.8f);
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay); protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay);
private class ScrollingInfo : IScrollingInfo
{
public readonly Bindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
IBindable<ScrollingDirection> IScrollingInfo.Direction => Direction;
}
} }
} }

View File

@ -0,0 +1,23 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Configuration;
using osu.Game.Rulesets.Mania.Configuration;
using osu.Game.Rulesets.UI.Scrolling;
namespace osu.Game.Rulesets.Mania.UI
{
public class ManiaScrollingInfo : IScrollingInfo
{
private readonly Bindable<ManiaScrollingDirection> configDirection = new Bindable<ManiaScrollingDirection>();
public readonly Bindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
IBindable<ScrollingDirection> IScrollingInfo.Direction => Direction;
public ManiaScrollingInfo(ManiaConfigManager config)
{
config.BindWith(ManiaSetting.ScrollDirection, configDirection);
configDirection.BindValueChanged(v => Direction.Value = (ScrollingDirection)v, true);
}
}
}

View File

@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.UI
/// <summary> /// <summary>
/// A collection of <see cref="Column"/>s. /// A collection of <see cref="Column"/>s.
/// </summary> /// </summary>
internal class ManiaStage : ManiaScrollingPlayfield public class ManiaStage : ManiaScrollingPlayfield
{ {
public const float HIT_TARGET_POSITION = 50; public const float HIT_TARGET_POSITION = 50;

View File

@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.ComponentModel;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Overlays.Mods; using osu.Game.Overlays.Mods;
@ -13,11 +12,11 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Mods;
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Game.Rulesets.Osu; using NUnit.Framework;
using osu.Framework.Configuration;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Overlays.Mods.Sections; using osu.Game.Overlays.Mods.Sections;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Mania.Mods; using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using OpenTK.Graphics; using OpenTK.Graphics;
@ -50,11 +49,6 @@ namespace osu.Game.Tests.Visual
private void load(RulesetStore rulesets) private void load(RulesetStore rulesets)
{ {
this.rulesets = rulesets; this.rulesets = rulesets;
}
protected override void LoadComplete()
{
base.LoadComplete();
Add(modSelect = new TestModSelectOverlay Add(modSelect = new TestModSelectOverlay
{ {
@ -71,34 +65,25 @@ namespace osu.Game.Tests.Visual
Position = new Vector2(0, 25), Position = new Vector2(0, 25),
}); });
modDisplay.Current.UnbindBindings();
modDisplay.Current.BindTo(modSelect.SelectedMods); modDisplay.Current.BindTo(modSelect.SelectedMods);
AddStep("Toggle", modSelect.ToggleVisibility);
AddStep("Hide", modSelect.Hide);
AddStep("Show", modSelect.Show); AddStep("Show", modSelect.Show);
AddStep("Toggle", modSelect.ToggleVisibility);
foreach (var rulesetInfo in rulesets.AvailableRulesets) AddStep("Toggle", modSelect.ToggleVisibility);
{
Ruleset ruleset = rulesetInfo.CreateInstance();
AddStep($"switch to {ruleset.Description}", () => Ruleset.Value = rulesetInfo);
switch (ruleset)
{
case OsuRuleset or:
testOsuMods(or);
break;
case ManiaRuleset mr:
testManiaMods(mr);
break;
}
}
} }
private void testOsuMods(OsuRuleset ruleset) [Test]
public void TestOsuMods()
{ {
var easierMods = ruleset.GetModsFor(ModType.DifficultyReduction); var ruleset = rulesets.AvailableRulesets.First(r => r.ID == 0);
var harderMods = ruleset.GetModsFor(ModType.DifficultyIncrease); AddStep("change ruleset", () => { Ruleset.Value = ruleset; });
var assistMods = ruleset.GetModsFor(ModType.Automation);
var instance = ruleset.CreateInstance();
var easierMods = instance.GetModsFor(ModType.DifficultyReduction);
var harderMods = instance.GetModsFor(ModType.DifficultyIncrease);
var assistMods = instance.GetModsFor(ModType.Automation);
var noFailMod = easierMods.FirstOrDefault(m => m is OsuModNoFail); var noFailMod = easierMods.FirstOrDefault(m => m is OsuModNoFail);
var hiddenMod = harderMods.FirstOrDefault(m => m is OsuModHidden); var hiddenMod = harderMods.FirstOrDefault(m => m is OsuModHidden);
@ -120,9 +105,40 @@ namespace osu.Game.Tests.Visual
testUnimplementedMod(autoPilotMod); testUnimplementedMod(autoPilotMod);
} }
private void testManiaMods(ManiaRuleset ruleset) [Test]
public void TestManiaMods()
{ {
testRankedText(ruleset.GetModsFor(ModType.Conversion).First(m => m is ManiaModRandom)); var ruleset = rulesets.AvailableRulesets.First(r => r.ID == 3);
AddStep("change ruleset", () => { Ruleset.Value = ruleset; });
testRankedText(ruleset.CreateInstance().GetModsFor(ModType.Conversion).First(m => m is ManiaModRandom));
}
[Test]
public void TestRulesetChanges()
{
var rulesetOsu = rulesets.AvailableRulesets.First(r => r.ID == 0);
var rulesetMania = rulesets.AvailableRulesets.First(r => r.ID == 3);
AddStep("change ruleset to null", () => { Ruleset.Value = null; });
var instance = rulesetOsu.CreateInstance();
var easierMods = instance.GetModsFor(ModType.DifficultyReduction);
var noFailMod = easierMods.FirstOrDefault(m => m is OsuModNoFail);
AddStep("set mods externally", () => { modDisplay.Current.Value = new[] { noFailMod }; });
AddStep("change ruleset to osu", () => { Ruleset.Value = rulesetOsu; });
AddAssert("ensure mods still selected", () => modDisplay.Current.Value.Single(m => m is OsuModNoFail) != null);
AddStep("change ruleset to mania", () => { Ruleset.Value = rulesetMania; });
AddAssert("ensure mods not selected", () => !modDisplay.Current.Value.Any(m => m is OsuModNoFail));
AddStep("change ruleset to osu", () => { Ruleset.Value = rulesetOsu; });
AddAssert("ensure mods not selected", () => !modDisplay.Current.Value.Any());
} }
private void testSingleMod(Mod mod) private void testSingleMod(Mod mod)
@ -237,6 +253,8 @@ namespace osu.Game.Tests.Visual
private class TestModSelectOverlay : ModSelectOverlay private class TestModSelectOverlay : ModSelectOverlay
{ {
public new Bindable<IEnumerable<Mod>> SelectedMods => base.SelectedMods;
public ModButton GetModButton(Mod mod) public ModButton GetModButton(Mod mod)
{ {
var section = ModSectionsContainer.Children.Single(s => s.ModType == mod.Type); var section = ModSectionsContainer.Children.Single(s => s.ModType == mod.Type);

View File

@ -1,25 +1,61 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Threading;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
namespace osu.Game.Tests.Visual namespace osu.Game.Tests.Visual
{ {
public class TestCasePlayerLoader : OsuTestCase public class TestCasePlayerLoader : ManualInputManagerTestCase
{ {
private PlayerLoader loader;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase game) private void load(OsuGameBase game)
{ {
Beatmap.Value = new DummyWorkingBeatmap(game); Beatmap.Value = new DummyWorkingBeatmap(game);
AddStep("load dummy beatmap", () => Add(new PlayerLoader(new Player AddStep("load dummy beatmap", () => Add(loader = new PlayerLoader(new Player
{ {
AllowPause = false, AllowPause = false,
AllowLeadIn = false, AllowLeadIn = false,
AllowResults = false, AllowResults = false,
}))); })));
AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre));
AddUntilStep(() => !loader.IsCurrentScreen, "wait for no longer current");
AddStep("load slow dummy beatmap", () =>
{
SlowLoadPlayer slow;
Add(loader = new PlayerLoader(slow = new SlowLoadPlayer
{
AllowPause = false,
AllowLeadIn = false,
AllowResults = false,
}));
Scheduler.AddDelayed(() => slow.Ready = true, 5000);
});
AddUntilStep(() => !loader.IsCurrentScreen, "wait for no longer current");
}
protected class SlowLoadPlayer : Player
{
public bool Ready;
[BackgroundDependencyLoader]
private void load()
{
while (!Ready)
Thread.Sleep(1);
}
} }
} }
} }

View File

@ -99,7 +99,9 @@ namespace osu.Game
private readonly List<OverlayContainer> overlays = new List<OverlayContainer>(); private readonly List<OverlayContainer> overlays = new List<OverlayContainer>();
// todo: move this to SongSelect once Screen has the ability to unsuspend. // todo: move this to SongSelect once Screen has the ability to unsuspend.
public readonly Bindable<IEnumerable<Mod>> SelectedMods = new Bindable<IEnumerable<Mod>>(new List<Mod>()); [Cached]
[Cached(Type = typeof(IBindable<IEnumerable<Mod>>))]
private readonly Bindable<IEnumerable<Mod>> selectedMods = new Bindable<IEnumerable<Mod>>(new Mod[] { });
public OsuGame(string[] args = null) public OsuGame(string[] args = null)
{ {

View File

@ -39,9 +39,39 @@ namespace osu.Game.Overlays.Mods
protected readonly FillFlowContainer<ModSection> ModSectionsContainer; protected readonly FillFlowContainer<ModSection> ModSectionsContainer;
public readonly Bindable<IEnumerable<Mod>> SelectedMods = new Bindable<IEnumerable<Mod>>(); protected readonly Bindable<IEnumerable<Mod>> SelectedMods = new Bindable<IEnumerable<Mod>>(new Mod[] { });
public readonly IBindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>(); protected readonly IBindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
[BackgroundDependencyLoader(true)]
private void load(OsuColour colours, IBindable<RulesetInfo> ruleset, AudioManager audio, Bindable<IEnumerable<Mod>> selectedMods)
{
LowMultiplierColour = colours.Red;
HighMultiplierColour = colours.Green;
UnrankedLabel.Colour = colours.Blue;
Ruleset.BindTo(ruleset);
if (selectedMods != null) SelectedMods.BindTo(selectedMods);
sampleOn = audio.Sample.Get(@"UI/check-on");
sampleOff = audio.Sample.Get(@"UI/check-off");
}
protected override void LoadComplete()
{
base.LoadComplete();
Ruleset.BindValueChanged(rulesetChanged, true);
SelectedMods.BindValueChanged(selectedModsChanged, true);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
Ruleset.UnbindAll();
SelectedMods.UnbindAll();
}
private void rulesetChanged(RulesetInfo newRuleset) private void rulesetChanged(RulesetInfo newRuleset)
{ {
@ -51,33 +81,16 @@ namespace osu.Game.Overlays.Mods
foreach (ModSection section in ModSectionsContainer.Children) foreach (ModSection section in ModSectionsContainer.Children)
section.Mods = instance.GetModsFor(section.ModType); section.Mods = instance.GetModsFor(section.ModType);
// attempt to re-select any already selected mods.
// this may be the first time we are receiving the ruleset, in which case they will still match.
selectedModsChanged(SelectedMods.Value);
// write the mods back to the SelectedMods bindable in the case a change was not applicable.
// this generally isn't required as the previous line will perform deselection; just here for safety.
refreshSelectedMods(); refreshSelectedMods();
} }
[BackgroundDependencyLoader]
private void load(OsuColour colours, IBindable<RulesetInfo> ruleset, AudioManager audio)
{
SelectedMods.ValueChanged += selectedModsChanged;
LowMultiplierColour = colours.Red;
HighMultiplierColour = colours.Green;
UnrankedLabel.Colour = colours.Blue;
Ruleset.BindTo(ruleset);
Ruleset.BindValueChanged(rulesetChanged, true);
sampleOn = audio.Sample.Get(@"UI/check-on");
sampleOff = audio.Sample.Get(@"UI/check-off");
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
Ruleset.UnbindAll();
SelectedMods.UnbindAll();
}
private void selectedModsChanged(IEnumerable<Mod> obj) private void selectedModsChanged(IEnumerable<Mod> obj)
{ {
foreach (ModSection section in ModSectionsContainer.Children) foreach (ModSection section in ModSectionsContainer.Children)
@ -176,10 +189,7 @@ namespace osu.Game.Overlays.Mods
refreshSelectedMods(); refreshSelectedMods();
} }
private void refreshSelectedMods() private void refreshSelectedMods() => SelectedMods.Value = ModSectionsContainer.Children.SelectMany(s => s.SelectedMods).ToArray();
{
SelectedMods.Value = ModSectionsContainer.Children.SelectMany(s => s.SelectedMods).ToArray();
}
public ModSelectOverlay() public ModSelectOverlay()
{ {

View File

@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Configuration;
using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
@ -23,12 +24,15 @@ namespace osu.Game.Rulesets.Edit
{ {
private readonly Ruleset ruleset; private readonly Ruleset ruleset;
public IEnumerable<DrawableHitObject> HitObjects => rulesetContainer.Playfield.AllHitObjects;
protected ICompositionTool CurrentTool { get; private set; } protected ICompositionTool CurrentTool { get; private set; }
protected IRulesetConfigManager Config { get; private set; }
private readonly List<Container> layerContainers = new List<Container>();
private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
private RulesetContainer rulesetContainer; private RulesetContainer rulesetContainer;
private readonly List<Container> layerContainers = new List<Container>();
private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
protected HitObjectComposer(Ruleset ruleset) protected HitObjectComposer(Ruleset ruleset)
{ {
@ -60,7 +64,7 @@ namespace osu.Game.Rulesets.Edit
}; };
var layerAboveRuleset = CreateLayerContainer(); var layerAboveRuleset = CreateLayerContainer();
layerAboveRuleset.Child = new HitObjectMaskLayer(rulesetContainer.Playfield, this); layerAboveRuleset.Child = new HitObjectMaskLayer();
layerContainers.Add(layerBelowRuleset); layerContainers.Add(layerBelowRuleset);
layerContainers.Add(layerAboveRuleset); layerContainers.Add(layerAboveRuleset);
@ -110,6 +114,16 @@ namespace osu.Game.Rulesets.Edit
toolboxCollection.Items[0].Select(); toolboxCollection.Items[0].Select();
} }
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.CacheAs(this);
Config = dependencies.Get<RulesetConfigCache>().GetConfigFor(ruleset);
return dependencies;
}
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();

View File

@ -8,6 +8,16 @@ namespace osu.Game.Rulesets.Edit.Tools
public class HitObjectCompositionTool<T> : ICompositionTool public class HitObjectCompositionTool<T> : ICompositionTool
where T : HitObject where T : HitObject
{ {
public string Name => typeof(T).Name; public string Name { get; }
public HitObjectCompositionTool()
: this(typeof(T).Name)
{
}
public HitObjectCompositionTool(string name)
{
Name = name;
}
} }
} }

View File

@ -1,10 +1,13 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Configuration; using osu.Framework.Configuration;
namespace osu.Game.Rulesets.UI namespace osu.Game.Rulesets.UI
@ -12,15 +15,21 @@ namespace osu.Game.Rulesets.UI
public abstract class Playfield : ScalableContainer public abstract class Playfield : ScalableContainer
{ {
/// <summary> /// <summary>
/// The HitObjects contained in this Playfield. /// The <see cref="DrawableHitObject"/> contained in this Playfield.
/// </summary> /// </summary>
public HitObjectContainer HitObjects { get; private set; } public HitObjectContainer HitObjects { get; private set; }
/// <summary> /// <summary>
/// All the <see cref="Playfield"/>s nested inside this playfield. /// All the <see cref="DrawableHitObject"/>s contained in this <see cref="Playfield"/> and all <see cref="NestedPlayfields"/>.
/// </summary> /// </summary>
public IReadOnlyList<Playfield> NestedPlayfields => nestedPlayfields; public IEnumerable<DrawableHitObject> AllHitObjects => HitObjects?.Objects.Concat(NestedPlayfields.SelectMany(p => p.AllHitObjects)) ?? Enumerable.Empty<DrawableHitObject>();
private List<Playfield> nestedPlayfields;
/// <summary>
/// All <see cref="Playfield"/>s nested inside this <see cref="Playfield"/>.
/// </summary>
public IEnumerable<Playfield> NestedPlayfields => nestedPlayfields.IsValueCreated ? nestedPlayfields.Value : Enumerable.Empty<Playfield>();
private readonly Lazy<List<Playfield>> nestedPlayfields = new Lazy<List<Playfield>>();
/// <summary> /// <summary>
/// Whether judgements should be displayed by this and and all nested <see cref="Playfield"/>s. /// Whether judgements should be displayed by this and and all nested <see cref="Playfield"/>s.
@ -54,7 +63,7 @@ namespace osu.Game.Rulesets.UI
/// <summary> /// <summary>
/// Performs post-processing tasks (if any) after all DrawableHitObjects are loaded into this Playfield. /// Performs post-processing tasks (if any) after all DrawableHitObjects are loaded into this Playfield.
/// </summary> /// </summary>
public virtual void PostProcess() => nestedPlayfields?.ForEach(p => p.PostProcess()); public virtual void PostProcess() => NestedPlayfields.ForEach(p => p.PostProcess());
/// <summary> /// <summary>
/// Adds a DrawableHitObject to this Playfield. /// Adds a DrawableHitObject to this Playfield.
@ -75,12 +84,8 @@ namespace osu.Game.Rulesets.UI
/// <param name="otherPlayfield">The <see cref="Playfield"/> to add.</param> /// <param name="otherPlayfield">The <see cref="Playfield"/> to add.</param>
protected void AddNested(Playfield otherPlayfield) protected void AddNested(Playfield otherPlayfield)
{ {
if (nestedPlayfields == null)
nestedPlayfields = new List<Playfield>();
nestedPlayfields.Add(otherPlayfield);
otherPlayfield.DisplayJudgements.BindTo(DisplayJudgements); otherPlayfield.DisplayJudgements.BindTo(DisplayJudgements);
nestedPlayfields.Value.Add(otherPlayfield);
} }
/// <summary> /// <summary>

View File

@ -1,7 +1,6 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
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;
@ -9,30 +8,24 @@ using osu.Framework.Input.EventArgs;
using osu.Framework.Input.States; using osu.Framework.Input.States;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI;
namespace osu.Game.Screens.Edit.Screens.Compose.Layers namespace osu.Game.Screens.Edit.Screens.Compose.Layers
{ {
public class HitObjectMaskLayer : CompositeDrawable public class HitObjectMaskLayer : CompositeDrawable
{ {
private readonly Playfield playfield;
private readonly HitObjectComposer composer;
private MaskContainer maskContainer; private MaskContainer maskContainer;
private HitObjectComposer composer;
public HitObjectMaskLayer(Playfield playfield, HitObjectComposer composer) public HitObjectMaskLayer()
{ {
// we need the playfield as HitObjects may not be initialised until its BDL.
this.playfield = playfield;
this.composer = composer;
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load(HitObjectComposer composer)
{ {
this.composer = composer;
maskContainer = new MaskContainer(); maskContainer = new MaskContainer();
var maskSelection = composer.CreateMaskSelection(); var maskSelection = composer.CreateMaskSelection();
@ -55,7 +48,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
dragLayer.CreateProxy() dragLayer.CreateProxy()
}; };
foreach (var obj in playfield.HitObjects.Objects) foreach (var obj in composer.HitObjects)
addMask(obj); addMask(obj);
} }
@ -77,18 +70,5 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
maskContainer.Add(mask); maskContainer.Add(mask);
} }
/// <summary>
/// Removes the mask for a <see cref="DrawableHitObject"/>.
/// </summary>
/// <param name="hitObject">The <see cref="DrawableHitObject"/> to remove the mask for.</param>
private void removeMask(DrawableHitObject hitObject)
{
var mask = maskContainer.FirstOrDefault(h => h.HitObject == hitObject);
if (mask == null)
return;
maskContainer.Remove(mask);
}
} }
} }

View File

@ -14,9 +14,11 @@ using osu.Framework.Threading;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Screens.Play.PlayerSettings;
using OpenTK; using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Screens.Play namespace osu.Game.Screens.Play
{ {
@ -69,21 +71,25 @@ namespace osu.Game.Screens.Play
} }
}); });
loadTask = LoadComponentAsync(player); loadTask = LoadComponentAsync(player, playerLoaded);
} }
private void playerLoaded(Player player) => info.Loading = false;
protected override void OnResuming(Screen last) protected override void OnResuming(Screen last)
{ {
base.OnResuming(last); base.OnResuming(last);
contentIn(); contentIn();
info.Loading = true;
//we will only be resumed if the player has requested a re-run (see ValidForResume setting above) //we will only be resumed if the player has requested a re-run (see ValidForResume setting above)
loadTask = LoadComponentAsync(player = new Player loadTask = LoadComponentAsync(player = new Player
{ {
RestartCount = player.RestartCount + 1, RestartCount = player.RestartCount + 1,
RestartRequested = player.RestartRequested, RestartRequested = player.RestartRequested,
}); }, playerLoaded);
this.Delay(400).Schedule(pushWhenLoaded); this.Delay(400).Schedule(pushWhenLoaded);
} }
@ -258,6 +264,25 @@ namespace osu.Game.Screens.Play
} }
private readonly WorkingBeatmap beatmap; private readonly WorkingBeatmap beatmap;
private LoadingAnimation loading;
private Sprite backgroundSprite;
public bool Loading
{
set
{
if (value)
{
loading.Show();
backgroundSprite.FadeColour(OsuColour.Gray(0.5f), 400, Easing.OutQuint);
}
else
{
loading.Hide();
backgroundSprite.FadeColour(Color4.White, 400, Easing.OutQuint);
}
}
}
public BeatmapMetadataDisplay(WorkingBeatmap beatmap) public BeatmapMetadataDisplay(WorkingBeatmap beatmap)
{ {
@ -304,9 +329,9 @@ namespace osu.Game.Screens.Play
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
CornerRadius = 10, CornerRadius = 10,
Masking = true, Masking = true,
Children = new[] Children = new Drawable[]
{ {
new Sprite backgroundSprite = new Sprite
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Texture = beatmap?.Background, Texture = beatmap?.Background,
@ -314,6 +339,7 @@ namespace osu.Game.Screens.Play
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
FillMode = FillMode.Fill, FillMode = FillMode.Fill,
}, },
loading = new LoadingAnimation { Scale = new Vector2(1.3f) }
} }
}, },
new OsuSpriteText new OsuSpriteText
@ -341,6 +367,8 @@ namespace osu.Game.Screens.Play
}, },
} }
}; };
Loading = true;
} }
} }
} }

View File

@ -50,13 +50,14 @@ namespace osu.Game.Screens.Select
private SampleChannel sampleConfirm; private SampleChannel sampleConfirm;
public readonly Bindable<IEnumerable<Mod>> SelectedMods = new Bindable<IEnumerable<Mod>>(new List<Mod>()); [Cached]
[Cached(Type = typeof(IBindable<IEnumerable<Mod>>))]
private readonly Bindable<IEnumerable<Mod>> selectedMods = new Bindable<IEnumerable<Mod>>(new Mod[] { });
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(OsuColour colours, AudioManager audio, BeatmapManager beatmaps, DialogOverlay dialogOverlay, OsuGame osu) private void load(OsuColour colours, AudioManager audio, BeatmapManager beatmaps, DialogOverlay dialogOverlay, Bindable<IEnumerable<Mod>> selectedMods)
{ {
if (osu != null) SelectedMods.BindTo(osu.SelectedMods); if (selectedMods != null) this.selectedMods.BindTo(selectedMods);
modSelect.SelectedMods.BindTo(SelectedMods);
sampleConfirm = audio.Sample.Get(@"SongSelect/confirm-selection"); sampleConfirm = audio.Sample.Get(@"SongSelect/confirm-selection");
@ -84,7 +85,7 @@ namespace osu.Game.Screens.Select
protected override void UpdateBeatmap(WorkingBeatmap beatmap) protected override void UpdateBeatmap(WorkingBeatmap beatmap)
{ {
beatmap.Mods.BindTo(SelectedMods); beatmap.Mods.BindTo(selectedMods);
base.UpdateBeatmap(beatmap); base.UpdateBeatmap(beatmap);
@ -131,7 +132,7 @@ namespace osu.Game.Screens.Select
if (Beatmap.Value.Track != null) if (Beatmap.Value.Track != null)
Beatmap.Value.Track.Looping = false; Beatmap.Value.Track.Looping = false;
SelectedMods.UnbindAll(); selectedMods.UnbindAll();
Beatmap.Value.Mods.Value = new Mod[] { }; Beatmap.Value.Mods.Value = new Mod[] { };
return false; return false;
@ -147,10 +148,10 @@ namespace osu.Game.Screens.Select
var auto = Ruleset.Value.CreateInstance().GetAutoplayMod(); var auto = Ruleset.Value.CreateInstance().GetAutoplayMod();
var autoType = auto.GetType(); var autoType = auto.GetType();
var mods = modSelect.SelectedMods.Value; var mods = selectedMods.Value;
if (mods.All(m => m.GetType() != autoType)) if (mods.All(m => m.GetType() != autoType))
{ {
modSelect.SelectedMods.Value = mods.Append(auto); selectedMods.Value = mods.Append(auto);
removeAutoModOnResume = true; removeAutoModOnResume = true;
} }
} }

View File

@ -18,7 +18,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.1" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="ppy.osu.Framework" Version="2018.803.0" /> <PackageReference Include="ppy.osu.Framework" Version="2018.806.0" />
<PackageReference Include="SharpCompress" Version="0.22.0" /> <PackageReference Include="SharpCompress" Version="0.22.0" />
<PackageReference Include="NUnit" Version="3.10.1" /> <PackageReference Include="NUnit" Version="3.10.1" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />