mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 14:25:05 +08:00
Merge branch 'master' into allow-reversing-spinners
This commit is contained in:
commit
3985fb1fa7
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
@ -12,8 +11,8 @@ namespace osu.Game.Rulesets.Mania.Edit
|
|||||||
{
|
{
|
||||||
public class ManiaBlueprintContainer : ComposeBlueprintContainer
|
public class ManiaBlueprintContainer : ComposeBlueprintContainer
|
||||||
{
|
{
|
||||||
public ManiaBlueprintContainer(IEnumerable<DrawableHitObject> drawableHitObjects)
|
public ManiaBlueprintContainer(HitObjectComposer composer)
|
||||||
: base(drawableHitObjects)
|
: base(composer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
|||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osu.Game.Screens.Edit.Compose.Components;
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
@ -89,8 +88,8 @@ namespace osu.Game.Rulesets.Mania.Edit
|
|||||||
return drawableRuleset;
|
return drawableRuleset;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override ComposeBlueprintContainer CreateBlueprintContainer(IEnumerable<DrawableHitObject> hitObjects)
|
protected override ComposeBlueprintContainer CreateBlueprintContainer()
|
||||||
=> new ManiaBlueprintContainer(hitObjects);
|
=> new ManiaBlueprintContainer(this);
|
||||||
|
|
||||||
protected override IReadOnlyList<HitObjectCompositionTool> CompositionTools => new HitObjectCompositionTool[]
|
protected override IReadOnlyList<HitObjectCompositionTool> CompositionTools => new HitObjectCompositionTool[]
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using 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.Osu.Edit.Blueprints.HitCircles;
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles;
|
||||||
@ -14,8 +13,8 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
{
|
{
|
||||||
public class OsuBlueprintContainer : ComposeBlueprintContainer
|
public class OsuBlueprintContainer : ComposeBlueprintContainer
|
||||||
{
|
{
|
||||||
public OsuBlueprintContainer(IEnumerable<DrawableHitObject> drawableHitObjects)
|
public OsuBlueprintContainer(HitObjectComposer composer)
|
||||||
: base(drawableHitObjects)
|
: base(composer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@ using osu.Game.Rulesets.Edit;
|
|||||||
using osu.Game.Rulesets.Edit.Tools;
|
using osu.Game.Rulesets.Edit.Tools;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Screens.Edit.Components.TernaryButtons;
|
using osu.Game.Screens.Edit.Components.TernaryButtons;
|
||||||
@ -80,8 +79,8 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
updateDistanceSnapGrid();
|
updateDistanceSnapGrid();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override ComposeBlueprintContainer CreateBlueprintContainer(IEnumerable<DrawableHitObject> hitObjects)
|
protected override ComposeBlueprintContainer CreateBlueprintContainer()
|
||||||
=> new OsuBlueprintContainer(hitObjects);
|
=> new OsuBlueprintContainer(this);
|
||||||
|
|
||||||
private DistanceSnapGrid distanceSnapGrid;
|
private DistanceSnapGrid distanceSnapGrid;
|
||||||
private Container distanceSnapGridContainer;
|
private Container distanceSnapGridContainer;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using 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.Taiko.Edit.Blueprints;
|
using osu.Game.Rulesets.Taiko.Edit.Blueprints;
|
||||||
@ -11,8 +10,8 @@ namespace osu.Game.Rulesets.Taiko.Edit
|
|||||||
{
|
{
|
||||||
public class TaikoBlueprintContainer : ComposeBlueprintContainer
|
public class TaikoBlueprintContainer : ComposeBlueprintContainer
|
||||||
{
|
{
|
||||||
public TaikoBlueprintContainer(IEnumerable<DrawableHitObject> hitObjects)
|
public TaikoBlueprintContainer(HitObjectComposer composer)
|
||||||
: base(hitObjects)
|
: base(composer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Tools;
|
using osu.Game.Rulesets.Edit.Tools;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
using osu.Game.Screens.Edit.Compose.Components;
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
|
|
||||||
@ -24,7 +23,7 @@ namespace osu.Game.Rulesets.Taiko.Edit
|
|||||||
new SwellCompositionTool()
|
new SwellCompositionTool()
|
||||||
};
|
};
|
||||||
|
|
||||||
protected override ComposeBlueprintContainer CreateBlueprintContainer(IEnumerable<DrawableHitObject> hitObjects)
|
protected override ComposeBlueprintContainer CreateBlueprintContainer()
|
||||||
=> new TaikoBlueprintContainer(hitObjects);
|
=> new TaikoBlueprintContainer(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneTimelineBlueprintContainer : TimelineTestScene
|
public class TestSceneTimelineBlueprintContainer : TimelineTestScene
|
||||||
{
|
{
|
||||||
public override Drawable CreateTestComponent() => new TimelineBlueprintContainer();
|
public override Drawable CreateTestComponent() => new TimelineBlueprintContainer(Composer);
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
|
@ -21,21 +21,25 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
{
|
{
|
||||||
protected TimelineArea TimelineArea { get; private set; }
|
protected TimelineArea TimelineArea { get; private set; }
|
||||||
|
|
||||||
|
protected HitObjectComposer Composer { get; private set; }
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(AudioManager audio)
|
private void load(AudioManager audio)
|
||||||
{
|
{
|
||||||
Beatmap.Value = new WaveformTestBeatmap(audio);
|
Beatmap.Value = new WaveformTestBeatmap(audio);
|
||||||
|
|
||||||
var playable = Beatmap.Value.GetPlayableBeatmap(Beatmap.Value.BeatmapInfo.Ruleset);
|
var playable = Beatmap.Value.GetPlayableBeatmap(Beatmap.Value.BeatmapInfo.Ruleset);
|
||||||
|
|
||||||
var editorBeatmap = new EditorBeatmap(playable);
|
var editorBeatmap = new EditorBeatmap(playable);
|
||||||
|
|
||||||
Dependencies.Cache(editorBeatmap);
|
Dependencies.Cache(editorBeatmap);
|
||||||
Dependencies.CacheAs<IBeatSnapProvider>(editorBeatmap);
|
Dependencies.CacheAs<IBeatSnapProvider>(editorBeatmap);
|
||||||
|
|
||||||
|
Composer = playable.BeatmapInfo.Ruleset.CreateInstance().CreateHitObjectComposer().With(d => d.Alpha = 0);
|
||||||
|
|
||||||
AddRange(new Drawable[]
|
AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
editorBeatmap,
|
editorBeatmap,
|
||||||
|
Composer,
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Gameplay
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
@ -21,8 +22,14 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
protected override void AddCheckSteps()
|
protected override void AddCheckSteps()
|
||||||
{
|
{
|
||||||
AddUntilStep("wait for fail", () => Player.HasFailed);
|
AddUntilStep("wait for fail", () => Player.HasFailed);
|
||||||
AddUntilStep("wait for multiple judged objects", () => ((FailPlayer)Player).DrawableRuleset.Playfield.AllHitObjects.Count(h => h.AllJudged) > 1);
|
AddUntilStep("wait for multiple judgements", () => ((FailPlayer)Player).ScoreProcessor.JudgedHits > 1);
|
||||||
AddAssert("total judgements == 1", () => ((FailPlayer)Player).HealthProcessor.JudgedHits >= 1);
|
AddAssert("total number of results == 1", () =>
|
||||||
|
{
|
||||||
|
var score = new ScoreInfo();
|
||||||
|
((FailPlayer)Player).ScoreProcessor.PopulateScore(score);
|
||||||
|
|
||||||
|
return score.Statistics.Values.Sum() == 1;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FailPlayer : TestPlayer
|
private class FailPlayer : TestPlayer
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Screens;
|
using osu.Game.Screens;
|
||||||
using osu.Game.Screens.Menu;
|
using osu.Game.Screens.Menu;
|
||||||
@ -73,6 +76,22 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
AddAssert("did perform", () => actionPerformed);
|
AddAssert("did perform", () => actionPerformed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestOverlaysAlwaysClosed()
|
||||||
|
{
|
||||||
|
ChatOverlay chat = null;
|
||||||
|
AddUntilStep("is at menu", () => Game.ScreenStack.CurrentScreen is MainMenu);
|
||||||
|
AddUntilStep("wait for chat load", () => (chat = Game.ChildrenOfType<ChatOverlay>().SingleOrDefault()) != null);
|
||||||
|
|
||||||
|
AddStep("show chat", () => InputManager.Key(Key.F8));
|
||||||
|
|
||||||
|
AddStep("try to perform", () => Game.PerformFromScreen(_ => actionPerformed = true));
|
||||||
|
|
||||||
|
AddUntilStep("still at menu", () => Game.ScreenStack.CurrentScreen is MainMenu);
|
||||||
|
AddAssert("did perform", () => actionPerformed);
|
||||||
|
AddAssert("chat closed", () => chat.State.Value == Visibility.Hidden);
|
||||||
|
}
|
||||||
|
|
||||||
[TestCase(true)]
|
[TestCase(true)]
|
||||||
[TestCase(false)]
|
[TestCase(false)]
|
||||||
public void TestPerformBlockedByDialog(bool confirmed)
|
public void TestPerformBlockedByDialog(bool confirmed)
|
||||||
|
@ -8,10 +8,9 @@ using osu.Framework.Audio;
|
|||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.Formats;
|
|
||||||
using osu.Game.IO;
|
|
||||||
using osu.Game.IO.Archives;
|
using osu.Game.IO.Archives;
|
||||||
using osu.Game.Rulesets.Catch;
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Tests.Beatmaps;
|
using osu.Game.Tests.Beatmaps;
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
|
|
||||||
@ -25,8 +24,8 @@ namespace osu.Game.Tests
|
|||||||
private readonly Beatmap beatmap;
|
private readonly Beatmap beatmap;
|
||||||
private readonly ITrackStore trackStore;
|
private readonly ITrackStore trackStore;
|
||||||
|
|
||||||
public WaveformTestBeatmap(AudioManager audioManager)
|
public WaveformTestBeatmap(AudioManager audioManager, RulesetInfo rulesetInfo = null)
|
||||||
: this(audioManager, new WaveformBeatmap())
|
: this(audioManager, new TestBeatmap(rulesetInfo ?? new OsuRuleset().RulesetInfo))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,21 +62,5 @@ namespace osu.Game.Tests
|
|||||||
return reader.Filenames.First(f => f.EndsWith(".mp3", StringComparison.Ordinal));
|
return reader.Filenames.First(f => f.EndsWith(".mp3", StringComparison.Ordinal));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class WaveformBeatmap : TestBeatmap
|
|
||||||
{
|
|
||||||
public WaveformBeatmap()
|
|
||||||
: base(new CatchRuleset().RulesetInfo)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Beatmap CreateBeatmap()
|
|
||||||
{
|
|
||||||
using (var reader = getZipReader())
|
|
||||||
using (var beatmapStream = reader.GetStream(reader.Filenames.First(f => f.EndsWith(".osu", StringComparison.Ordinal))))
|
|
||||||
using (var beatmapReader = new LineBufferedReader(beatmapStream))
|
|
||||||
return Decoder.GetDecoder<Beatmap>(beatmapReader).Decode(beatmapReader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,8 @@ namespace osu.Game
|
|||||||
// a dialog may be blocking the execution for now.
|
// a dialog may be blocking the execution for now.
|
||||||
if (checkForDialog(current)) return;
|
if (checkForDialog(current)) return;
|
||||||
|
|
||||||
|
game.CloseAllOverlays(false);
|
||||||
|
|
||||||
// we may already be at the target screen type.
|
// we may already be at the target screen type.
|
||||||
if (validScreens.Contains(getCurrentScreen().GetType()) && !beatmap.Disabled)
|
if (validScreens.Contains(getCurrentScreen().GetType()) && !beatmap.Disabled)
|
||||||
{
|
{
|
||||||
@ -83,8 +85,6 @@ namespace osu.Game
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
game.CloseAllOverlays(false);
|
|
||||||
|
|
||||||
while (current != null)
|
while (current != null)
|
||||||
{
|
{
|
||||||
if (validScreens.Contains(current.GetType()))
|
if (validScreens.Contains(current.GetType()))
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.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;
|
||||||
@ -65,17 +64,13 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
|
|
||||||
private void addHitObject(HitObject hitObject)
|
private void addHitObject(HitObject hitObject)
|
||||||
{
|
{
|
||||||
var drawableObject = drawableRuleset.CreateDrawableRepresentation((TObject)hitObject);
|
drawableRuleset.AddHitObject((TObject)hitObject);
|
||||||
|
|
||||||
drawableRuleset.Playfield.Add(drawableObject);
|
|
||||||
drawableRuleset.Playfield.PostProcess();
|
drawableRuleset.Playfield.PostProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeHitObject(HitObject hitObject)
|
private void removeHitObject(HitObject hitObject)
|
||||||
{
|
{
|
||||||
var drawableObject = Playfield.AllHitObjects.Single(d => d.HitObject == hitObject);
|
drawableRuleset.RemoveHitObject((TObject)hitObject);
|
||||||
|
|
||||||
drawableRuleset.Playfield.Remove(drawableObject);
|
|
||||||
drawableRuleset.Playfield.PostProcess();
|
drawableRuleset.Playfield.PostProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
drawableRulesetWrapper,
|
drawableRulesetWrapper,
|
||||||
// layers above playfield
|
// layers above playfield
|
||||||
drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer()
|
drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer()
|
||||||
.WithChild(BlueprintContainer = CreateBlueprintContainer(HitObjects))
|
.WithChild(BlueprintContainer = CreateBlueprintContainer())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
@ -182,9 +182,8 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Construct a relevant blueprint container. This will manage hitobject selection/placement input handling and display logic.
|
/// Construct a relevant blueprint container. This will manage hitobject selection/placement input handling and display logic.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="hitObjects">A live collection of all <see cref="DrawableHitObject"/>s in the editor beatmap.</param>
|
protected virtual ComposeBlueprintContainer CreateBlueprintContainer()
|
||||||
protected virtual ComposeBlueprintContainer CreateBlueprintContainer(IEnumerable<DrawableHitObject> hitObjects)
|
=> new ComposeBlueprintContainer(this);
|
||||||
=> new ComposeBlueprintContainer(hitObjects);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Construct a drawable ruleset for the provided ruleset.
|
/// Construct a drawable ruleset for the provided ruleset.
|
||||||
|
@ -42,6 +42,32 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<DrawableHitObject, JudgementResult> RevertResult;
|
public event Action<DrawableHitObject, JudgementResult> RevertResult;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when a <see cref="HitObject"/> becomes used by a <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If this <see cref="HitObjectContainer"/> uses pooled objects, this represents the time when the <see cref="HitObject"/>s become alive.
|
||||||
|
/// </remarks>
|
||||||
|
internal event Action<HitObject> HitObjectUsageBegan;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when a <see cref="HitObject"/> becomes unused by a <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If this <see cref="HitObjectContainer"/> uses pooled objects, this represents the time when the <see cref="HitObject"/>s become dead.
|
||||||
|
/// </remarks>
|
||||||
|
internal event Action<HitObject> HitObjectUsageFinished;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The amount of time prior to the current time within which <see cref="HitObject"/>s should be considered alive.
|
||||||
|
/// </summary>
|
||||||
|
internal double PastLifetimeExtension { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The amount of time after the current time within which <see cref="HitObject"/>s should be considered alive.
|
||||||
|
/// </summary>
|
||||||
|
internal double FutureLifetimeExtension { get; set; }
|
||||||
|
|
||||||
private readonly Dictionary<DrawableHitObject, IBindable> startTimeMap = new Dictionary<DrawableHitObject, IBindable>();
|
private readonly Dictionary<DrawableHitObject, IBindable> startTimeMap = new Dictionary<DrawableHitObject, IBindable>();
|
||||||
private readonly Dictionary<HitObjectLifetimeEntry, DrawableHitObject> drawableMap = new Dictionary<HitObjectLifetimeEntry, DrawableHitObject>();
|
private readonly Dictionary<HitObjectLifetimeEntry, DrawableHitObject> drawableMap = new Dictionary<HitObjectLifetimeEntry, DrawableHitObject>();
|
||||||
private readonly LifetimeEntryManager lifetimeManager = new LifetimeEntryManager();
|
private readonly LifetimeEntryManager lifetimeManager = new LifetimeEntryManager();
|
||||||
@ -88,6 +114,8 @@ namespace osu.Game.Rulesets.UI
|
|||||||
|
|
||||||
bindStartTime(drawable);
|
bindStartTime(drawable);
|
||||||
AddInternal(drawableMap[entry] = drawable, false);
|
AddInternal(drawableMap[entry] = drawable, false);
|
||||||
|
|
||||||
|
HitObjectUsageBegan?.Invoke(entry.HitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeDrawable(HitObjectLifetimeEntry entry)
|
private void removeDrawable(HitObjectLifetimeEntry entry)
|
||||||
@ -103,6 +131,8 @@ namespace osu.Game.Rulesets.UI
|
|||||||
|
|
||||||
unbindStartTime(drawable);
|
unbindStartTime(drawable);
|
||||||
RemoveInternal(drawable);
|
RemoveInternal(drawable);
|
||||||
|
|
||||||
|
HitObjectUsageFinished?.Invoke(entry.HitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -159,7 +189,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
protected override bool CheckChildrenLife()
|
protected override bool CheckChildrenLife()
|
||||||
{
|
{
|
||||||
bool aliveChanged = base.CheckChildrenLife();
|
bool aliveChanged = base.CheckChildrenLife();
|
||||||
aliveChanged |= lifetimeManager.Update(Time.Current, Time.Current);
|
aliveChanged |= lifetimeManager.Update(Time.Current - PastLifetimeExtension, Time.Current + FutureLifetimeExtension);
|
||||||
return aliveChanged;
|
return aliveChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +88,8 @@ namespace osu.Game.Rulesets.UI
|
|||||||
{
|
{
|
||||||
h.NewResult += (d, r) => NewResult?.Invoke(d, r);
|
h.NewResult += (d, r) => NewResult?.Invoke(d, r);
|
||||||
h.RevertResult += (d, r) => RevertResult?.Invoke(d, r);
|
h.RevertResult += (d, r) => RevertResult?.Invoke(d, r);
|
||||||
|
h.HitObjectUsageBegan += o => HitObjectUsageBegan?.Invoke(o);
|
||||||
|
h.HitObjectUsageFinished += o => HitObjectUsageFinished?.Invoke(o);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,6 +145,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
public virtual void Add(HitObjectLifetimeEntry entry)
|
public virtual void Add(HitObjectLifetimeEntry entry)
|
||||||
{
|
{
|
||||||
HitObjectContainer.Add(entry);
|
HitObjectContainer.Add(entry);
|
||||||
|
lifetimeEntryMap[entry.HitObject] = entry;
|
||||||
OnHitObjectAdded(entry.HitObject);
|
OnHitObjectAdded(entry.HitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,6 +158,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
{
|
{
|
||||||
if (HitObjectContainer.Remove(entry))
|
if (HitObjectContainer.Remove(entry))
|
||||||
{
|
{
|
||||||
|
lifetimeEntryMap.Remove(entry.HitObject);
|
||||||
OnHitObjectRemoved(entry.HitObject);
|
OnHitObjectRemoved(entry.HitObject);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -208,6 +212,8 @@ namespace osu.Game.Rulesets.UI
|
|||||||
|
|
||||||
otherPlayfield.NewResult += (d, r) => NewResult?.Invoke(d, r);
|
otherPlayfield.NewResult += (d, r) => NewResult?.Invoke(d, r);
|
||||||
otherPlayfield.RevertResult += (d, r) => RevertResult?.Invoke(d, r);
|
otherPlayfield.RevertResult += (d, r) => RevertResult?.Invoke(d, r);
|
||||||
|
otherPlayfield.HitObjectUsageBegan += h => HitObjectUsageBegan?.Invoke(h);
|
||||||
|
otherPlayfield.HitObjectUsageFinished += h => HitObjectUsageFinished?.Invoke(h);
|
||||||
|
|
||||||
nestedPlayfields.Value.Add(otherPlayfield);
|
nestedPlayfields.Value.Add(otherPlayfield);
|
||||||
}
|
}
|
||||||
@ -240,6 +246,99 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual HitObjectContainer CreateHitObjectContainer() => new HitObjectContainer();
|
protected virtual HitObjectContainer CreateHitObjectContainer() => new HitObjectContainer();
|
||||||
|
|
||||||
|
#region Editor logic
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when a <see cref="HitObject"/> becomes used by a <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If this <see cref="HitObjectContainer"/> uses pooled objects, this represents the time when the <see cref="HitObject"/>s become alive.
|
||||||
|
/// </remarks>
|
||||||
|
internal event Action<HitObject> HitObjectUsageBegan;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when a <see cref="HitObject"/> becomes unused by a <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If this <see cref="HitObjectContainer"/> uses pooled objects, this represents the time when the <see cref="HitObject"/>s become dead.
|
||||||
|
/// </remarks>
|
||||||
|
internal event Action<HitObject> HitObjectUsageFinished;
|
||||||
|
|
||||||
|
private readonly Dictionary<HitObject, HitObjectLifetimeEntry> lifetimeEntryMap = new Dictionary<HitObject, HitObjectLifetimeEntry>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets whether to keep a given <see cref="HitObject"/> always alive within this or any nested <see cref="Playfield"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hitObject">The <see cref="HitObject"/> to set.</param>
|
||||||
|
/// <param name="keepAlive">Whether to keep <paramref name="hitObject"/> always alive.</param>
|
||||||
|
internal void SetKeepAlive(HitObject hitObject, bool keepAlive)
|
||||||
|
{
|
||||||
|
if (lifetimeEntryMap.TryGetValue(hitObject, out var entry))
|
||||||
|
{
|
||||||
|
entry.KeepAlive = keepAlive;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nestedPlayfields.IsValueCreated)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var p in nestedPlayfields.Value)
|
||||||
|
p.SetKeepAlive(hitObject, keepAlive);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Keeps all <see cref="HitObject"/>s alive within this and all nested <see cref="Playfield"/>s.
|
||||||
|
/// </summary>
|
||||||
|
internal void KeepAllAlive()
|
||||||
|
{
|
||||||
|
foreach (var (_, entry) in lifetimeEntryMap)
|
||||||
|
entry.KeepAlive = true;
|
||||||
|
|
||||||
|
if (!nestedPlayfields.IsValueCreated)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var p in nestedPlayfields.Value)
|
||||||
|
p.KeepAllAlive();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The amount of time prior to the current time within which <see cref="HitObject"/>s should be considered alive.
|
||||||
|
/// </summary>
|
||||||
|
internal double PastLifetimeExtension
|
||||||
|
{
|
||||||
|
get => HitObjectContainer.PastLifetimeExtension;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
HitObjectContainer.PastLifetimeExtension = value;
|
||||||
|
|
||||||
|
if (!nestedPlayfields.IsValueCreated)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var nested in nestedPlayfields.Value)
|
||||||
|
nested.PastLifetimeExtension = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The amount of time after the current time within which <see cref="HitObject"/>s should be considered alive.
|
||||||
|
/// </summary>
|
||||||
|
internal double FutureLifetimeExtension
|
||||||
|
{
|
||||||
|
get => HitObjectContainer.FutureLifetimeExtension;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
HitObjectContainer.FutureLifetimeExtension = value;
|
||||||
|
|
||||||
|
if (!nestedPlayfields.IsValueCreated)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var nested in nestedPlayfields.Value)
|
||||||
|
nested.FutureLifetimeExtension = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
public class InvisibleCursorContainer : GameplayCursorContainer
|
public class InvisibleCursorContainer : GameplayCursorContainer
|
||||||
{
|
{
|
||||||
protected override Drawable CreateCursor() => new InvisibleCursor();
|
protected override Drawable CreateCursor() => new InvisibleCursor();
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -34,6 +35,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
protected SelectionHandler SelectionHandler { get; private set; }
|
protected SelectionHandler SelectionHandler { get; private set; }
|
||||||
|
|
||||||
|
protected readonly HitObjectComposer Composer;
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private IEditorChangeHandler changeHandler { get; set; }
|
private IEditorChangeHandler changeHandler { get; set; }
|
||||||
|
|
||||||
@ -44,12 +47,15 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
protected EditorBeatmap Beatmap { get; private set; }
|
protected EditorBeatmap Beatmap { get; private set; }
|
||||||
|
|
||||||
private readonly BindableList<HitObject> selectedHitObjects = new BindableList<HitObject>();
|
private readonly BindableList<HitObject> selectedHitObjects = new BindableList<HitObject>();
|
||||||
|
private readonly Dictionary<HitObject, SelectionBlueprint> blueprintMap = new Dictionary<HitObject, SelectionBlueprint>();
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private IPositionSnapProvider snapProvider { get; set; }
|
private IPositionSnapProvider snapProvider { get; set; }
|
||||||
|
|
||||||
protected BlueprintContainer()
|
protected BlueprintContainer(HitObjectComposer composer)
|
||||||
{
|
{
|
||||||
|
Composer = composer;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,8 +74,12 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
DragBox.CreateProxy().With(p => p.Depth = float.MinValue)
|
DragBox.CreateProxy().With(p => p.Depth = float.MinValue)
|
||||||
});
|
});
|
||||||
|
|
||||||
foreach (var obj in Beatmap.HitObjects)
|
// For non-pooled rulesets, hitobjects are already present in the playfield which allows the blueprints to be loaded in the async context.
|
||||||
AddBlueprintFor(obj);
|
if (Composer != null)
|
||||||
|
{
|
||||||
|
foreach (var obj in Composer.HitObjects)
|
||||||
|
addBlueprintFor(obj.HitObject);
|
||||||
|
}
|
||||||
|
|
||||||
selectedHitObjects.BindTo(Beatmap.SelectedHitObjects);
|
selectedHitObjects.BindTo(Beatmap.SelectedHitObjects);
|
||||||
selectedHitObjects.CollectionChanged += (selectedObjects, args) =>
|
selectedHitObjects.CollectionChanged += (selectedObjects, args) =>
|
||||||
@ -94,8 +104,18 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
Beatmap.HitObjectAdded += AddBlueprintFor;
|
Beatmap.HitObjectAdded += addBlueprintFor;
|
||||||
Beatmap.HitObjectRemoved += removeBlueprintFor;
|
Beatmap.HitObjectRemoved += removeBlueprintFor;
|
||||||
|
|
||||||
|
if (Composer != null)
|
||||||
|
{
|
||||||
|
// For pooled rulesets, blueprints must be added for hitobjects already "current" as they would've not been "current" during the async load addition process above.
|
||||||
|
foreach (var obj in Composer.HitObjects)
|
||||||
|
addBlueprintFor(obj.HitObject);
|
||||||
|
|
||||||
|
Composer.Playfield.HitObjectUsageBegan += addBlueprintFor;
|
||||||
|
Composer.Playfield.HitObjectUsageFinished += removeBlueprintFor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual Container<SelectionBlueprint> CreateSelectionBlueprintContainer() =>
|
protected virtual Container<SelectionBlueprint> CreateSelectionBlueprintContainer() =>
|
||||||
@ -247,29 +267,17 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
#region Blueprint Addition/Removal
|
#region Blueprint Addition/Removal
|
||||||
|
|
||||||
private void removeBlueprintFor(HitObject hitObject)
|
private void addBlueprintFor(HitObject hitObject)
|
||||||
{
|
{
|
||||||
var blueprint = SelectionBlueprints.SingleOrDefault(m => m.HitObject == hitObject);
|
if (blueprintMap.ContainsKey(hitObject))
|
||||||
if (blueprint == null)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
blueprint.Deselect();
|
|
||||||
|
|
||||||
blueprint.Selected -= onBlueprintSelected;
|
|
||||||
blueprint.Deselected -= onBlueprintDeselected;
|
|
||||||
|
|
||||||
SelectionBlueprints.Remove(blueprint);
|
|
||||||
|
|
||||||
if (movementBlueprint == blueprint)
|
|
||||||
finishSelectionMovement();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void AddBlueprintFor(HitObject hitObject)
|
|
||||||
{
|
|
||||||
var blueprint = CreateBlueprintFor(hitObject);
|
var blueprint = CreateBlueprintFor(hitObject);
|
||||||
if (blueprint == null)
|
if (blueprint == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
blueprintMap[hitObject] = blueprint;
|
||||||
|
|
||||||
blueprint.Selected += onBlueprintSelected;
|
blueprint.Selected += onBlueprintSelected;
|
||||||
blueprint.Deselected += onBlueprintDeselected;
|
blueprint.Deselected += onBlueprintDeselected;
|
||||||
|
|
||||||
@ -277,6 +285,41 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
blueprint.Select();
|
blueprint.Select();
|
||||||
|
|
||||||
SelectionBlueprints.Add(blueprint);
|
SelectionBlueprints.Add(blueprint);
|
||||||
|
|
||||||
|
OnBlueprintAdded(hitObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeBlueprintFor(HitObject hitObject)
|
||||||
|
{
|
||||||
|
if (!blueprintMap.Remove(hitObject, out var blueprint))
|
||||||
|
return;
|
||||||
|
|
||||||
|
blueprint.Deselect();
|
||||||
|
blueprint.Selected -= onBlueprintSelected;
|
||||||
|
blueprint.Deselected -= onBlueprintDeselected;
|
||||||
|
|
||||||
|
SelectionBlueprints.Remove(blueprint);
|
||||||
|
|
||||||
|
if (movementBlueprint == blueprint)
|
||||||
|
finishSelectionMovement();
|
||||||
|
|
||||||
|
OnBlueprintRemoved(hitObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called after a <see cref="HitObject"/> blueprint has been added.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hitObject">The <see cref="HitObject"/> for which the blueprint has been added.</param>
|
||||||
|
protected virtual void OnBlueprintAdded(HitObject hitObject)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called after a <see cref="HitObject"/> blueprint has been removed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hitObject">The <see cref="HitObject"/> for which the blueprint has been removed.</param>
|
||||||
|
protected virtual void OnBlueprintRemoved(HitObject hitObject)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -349,7 +392,13 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Selects all <see cref="SelectionBlueprint"/>s.
|
/// Selects all <see cref="SelectionBlueprint"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void selectAll() => SelectionBlueprints.ToList().ForEach(m => m.Select());
|
private void selectAll()
|
||||||
|
{
|
||||||
|
Composer.Playfield.KeepAllAlive();
|
||||||
|
|
||||||
|
// Scheduled to allow the change in lifetime to take place.
|
||||||
|
Schedule(() => SelectionBlueprints.ToList().ForEach(m => m.Select()));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deselects all selected <see cref="SelectionBlueprint"/>s.
|
/// Deselects all selected <see cref="SelectionBlueprint"/>s.
|
||||||
@ -360,12 +409,16 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
{
|
{
|
||||||
SelectionHandler.HandleSelected(blueprint);
|
SelectionHandler.HandleSelected(blueprint);
|
||||||
SelectionBlueprints.ChangeChildDepth(blueprint, 1);
|
SelectionBlueprints.ChangeChildDepth(blueprint, 1);
|
||||||
|
|
||||||
|
Composer.Playfield.SetKeepAlive(blueprint.HitObject, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onBlueprintDeselected(SelectionBlueprint blueprint)
|
private void onBlueprintDeselected(SelectionBlueprint blueprint)
|
||||||
{
|
{
|
||||||
SelectionHandler.HandleDeselected(blueprint);
|
SelectionHandler.HandleDeselected(blueprint);
|
||||||
SelectionBlueprints.ChangeChildDepth(blueprint, 0);
|
SelectionBlueprints.ChangeChildDepth(blueprint, 0);
|
||||||
|
|
||||||
|
Composer.Playfield.SetKeepAlive(blueprint.HitObject, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -456,9 +509,15 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
if (Beatmap != null)
|
if (Beatmap != null)
|
||||||
{
|
{
|
||||||
Beatmap.HitObjectAdded -= AddBlueprintFor;
|
Beatmap.HitObjectAdded -= addBlueprintFor;
|
||||||
Beatmap.HitObjectRemoved -= removeBlueprintFor;
|
Beatmap.HitObjectRemoved -= removeBlueprintFor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Composer != null)
|
||||||
|
{
|
||||||
|
Composer.Playfield.HitObjectUsageBegan -= addBlueprintFor;
|
||||||
|
Composer.Playfield.HitObjectUsageFinished -= removeBlueprintFor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,23 +27,16 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ComposeBlueprintContainer : BlueprintContainer
|
public class ComposeBlueprintContainer : BlueprintContainer
|
||||||
{
|
{
|
||||||
[Resolved]
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
||||||
private HitObjectComposer composer { get; set; }
|
|
||||||
|
|
||||||
private PlacementBlueprint currentPlacement;
|
|
||||||
|
|
||||||
private readonly Container<PlacementBlueprint> placementBlueprintContainer;
|
private readonly Container<PlacementBlueprint> placementBlueprintContainer;
|
||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
private PlacementBlueprint currentPlacement;
|
||||||
|
|
||||||
private InputManager inputManager;
|
private InputManager inputManager;
|
||||||
|
|
||||||
private readonly IEnumerable<DrawableHitObject> drawableHitObjects;
|
public ComposeBlueprintContainer(HitObjectComposer composer)
|
||||||
|
: base(composer)
|
||||||
public ComposeBlueprintContainer(IEnumerable<DrawableHitObject> drawableHitObjects)
|
|
||||||
{
|
{
|
||||||
this.drawableHitObjects = drawableHitObjects;
|
|
||||||
|
|
||||||
placementBlueprintContainer = new Container<PlacementBlueprint>
|
placementBlueprintContainer = new Container<PlacementBlueprint>
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
@ -162,7 +155,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
private void updatePlacementPosition()
|
private void updatePlacementPosition()
|
||||||
{
|
{
|
||||||
var snapResult = composer.SnapScreenSpacePositionToValidTime(inputManager.CurrentState.Mouse.Position);
|
var snapResult = Composer.SnapScreenSpacePositionToValidTime(inputManager.CurrentState.Mouse.Position);
|
||||||
|
|
||||||
currentPlacement.UpdatePosition(snapResult);
|
currentPlacement.UpdatePosition(snapResult);
|
||||||
}
|
}
|
||||||
@ -173,7 +166,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
if (composer.CursorInPlacementArea)
|
if (Composer.CursorInPlacementArea)
|
||||||
createPlacement();
|
createPlacement();
|
||||||
else if (currentPlacement?.PlacementActive == false)
|
else if (currentPlacement?.PlacementActive == false)
|
||||||
removePlacement();
|
removePlacement();
|
||||||
@ -186,7 +179,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
protected sealed override SelectionBlueprint CreateBlueprintFor(HitObject hitObject)
|
protected sealed override SelectionBlueprint CreateBlueprintFor(HitObject hitObject)
|
||||||
{
|
{
|
||||||
var drawable = drawableHitObjects.FirstOrDefault(d => d.HitObject == hitObject);
|
var drawable = Composer.HitObjects.FirstOrDefault(d => d.HitObject == hitObject);
|
||||||
|
|
||||||
if (drawable == null)
|
if (drawable == null)
|
||||||
return null;
|
return null;
|
||||||
@ -196,11 +189,11 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
public virtual OverlaySelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject) => null;
|
public virtual OverlaySelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject) => null;
|
||||||
|
|
||||||
protected override void AddBlueprintFor(HitObject hitObject)
|
protected override void OnBlueprintAdded(HitObject hitObject)
|
||||||
{
|
{
|
||||||
refreshTool();
|
base.OnBlueprintAdded(hitObject);
|
||||||
|
|
||||||
base.AddBlueprintFor(hitObject);
|
refreshTool();
|
||||||
|
|
||||||
// on successful placement, the new combo button should be reset as this is the most common user interaction.
|
// on successful placement, the new combo button should be reset as this is the most common user interaction.
|
||||||
if (Beatmap.SelectedHitObjects.Count == 0)
|
if (Beatmap.SelectedHitObjects.Count == 0)
|
||||||
|
@ -219,6 +219,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private IBeatSnapProvider beatSnapProvider { get; set; }
|
private IBeatSnapProvider beatSnapProvider { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The total amount of time visible on the timeline.
|
||||||
|
/// </summary>
|
||||||
|
public double VisibleRange => track.Length / Zoom;
|
||||||
|
|
||||||
public SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition) =>
|
public SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition) =>
|
||||||
new SnapResult(screenSpacePosition, beatSnapProvider.SnapTime(getTimeFromPosition(Content.ToLocalSpace(screenSpacePosition))));
|
new SnapResult(screenSpacePosition, beatSnapProvider.SnapTime(getTimeFromPosition(Content.ToLocalSpace(screenSpacePosition))));
|
||||||
|
|
||||||
|
@ -26,12 +26,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
private EditorBeatmap beatmap { get; set; }
|
private EditorBeatmap beatmap { get; set; }
|
||||||
|
|
||||||
private DragEvent lastDragEvent;
|
private DragEvent lastDragEvent;
|
||||||
|
|
||||||
private Bindable<HitObject> placement;
|
private Bindable<HitObject> placement;
|
||||||
|
|
||||||
private SelectionBlueprint placementBlueprint;
|
private SelectionBlueprint placementBlueprint;
|
||||||
|
|
||||||
public TimelineBlueprintContainer()
|
public TimelineBlueprintContainer(HitObjectComposer composer)
|
||||||
|
: base(composer)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
@ -97,6 +96,12 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
if (lastDragEvent != null)
|
if (lastDragEvent != null)
|
||||||
OnDrag(lastDragEvent);
|
OnDrag(lastDragEvent);
|
||||||
|
|
||||||
|
if (Composer != null)
|
||||||
|
{
|
||||||
|
Composer.Playfield.PastLifetimeExtension = timeline.VisibleRange / 2;
|
||||||
|
Composer.Playfield.FutureLifetimeExtension = timeline.VisibleRange / 2;
|
||||||
|
}
|
||||||
|
|
||||||
base.Update();
|
base.Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,6 +53,6 @@ namespace osu.Game.Screens.Edit.Compose
|
|||||||
return beatmapSkinProvider.WithChild(rulesetSkinProvider.WithChild(composer));
|
return beatmapSkinProvider.WithChild(rulesetSkinProvider.WithChild(composer));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Drawable CreateTimelineContent() => composer == null ? base.CreateTimelineContent() : new TimelineBlueprintContainer();
|
protected override Drawable CreateTimelineContent() => composer == null ? base.CreateTimelineContent() : new TimelineBlueprintContainer(composer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user