Merge branch 'master' into fix-loaderanimation-testcase

This commit is contained in:
Dean Herbert
2019-03-29 14:55:00 +09:00
committed by GitHub
18 changed files with 54 additions and 41 deletions

View File

@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{ {
private readonly Container bananaContainer; private readonly Container bananaContainer;
public DrawableBananaShower(BananaShower s, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> getVisualRepresentation = null) public DrawableBananaShower(BananaShower s, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> createDrawableRepresentation = null)
: base(s) : base(s)
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
AddInternal(bananaContainer = new Container { RelativeSizeAxes = Axes.Both }); AddInternal(bananaContainer = new Container { RelativeSizeAxes = Axes.Both });
foreach (var b in s.NestedHitObjects.Cast<Banana>()) foreach (var b in s.NestedHitObjects.Cast<Banana>())
AddNested(getVisualRepresentation?.Invoke(b)); AddNested(createDrawableRepresentation?.Invoke(b));
} }
protected override void AddNested(DrawableHitObject h) protected override void AddNested(DrawableHitObject h)

View File

@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{ {
private readonly Container dropletContainer; private readonly Container dropletContainer;
public DrawableJuiceStream(JuiceStream s, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> getVisualRepresentation = null) public DrawableJuiceStream(JuiceStream s, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> createDrawableRepresentation = null)
: base(s) : base(s)
{ {
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
AddInternal(dropletContainer = new Container { RelativeSizeAxes = Axes.Both, }); AddInternal(dropletContainer = new Container { RelativeSizeAxes = Axes.Both, });
foreach (var o in s.NestedHitObjects.Cast<CatchHitObject>()) foreach (var o in s.NestedHitObjects.Cast<CatchHitObject>())
AddNested(getVisualRepresentation?.Invoke(o)); AddNested(createDrawableRepresentation?.Invoke(o));
} }
protected override void AddNested(DrawableHitObject h) protected override void AddNested(DrawableHitObject h)

View File

@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Catch.UI
internal readonly CatcherArea CatcherArea; internal readonly CatcherArea CatcherArea;
public CatchPlayfield(BeatmapDifficulty difficulty, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> getVisualRepresentation) public CatchPlayfield(BeatmapDifficulty difficulty, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> createDrawableRepresentation)
{ {
Container explodingFruitContainer; Container explodingFruitContainer;
@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Catch.UI
}, },
CatcherArea = new CatcherArea(difficulty) CatcherArea = new CatcherArea(difficulty)
{ {
GetVisualRepresentation = getVisualRepresentation, CreateDrawableRepresentation = createDrawableRepresentation,
ExplodingFruitTarget = explodingFruitContainer, ExplodingFruitTarget = explodingFruitContainer,
Anchor = Anchor.BottomLeft, Anchor = Anchor.BottomLeft,
Origin = Anchor.TopLeft, Origin = Anchor.TopLeft,

View File

@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Catch.UI
protected internal readonly Catcher MovableCatcher; protected internal readonly Catcher MovableCatcher;
public Func<CatchHitObject, DrawableHitObject<CatchHitObject>> GetVisualRepresentation; public Func<CatchHitObject, DrawableHitObject<CatchHitObject>> CreateDrawableRepresentation;
public Container ExplodingFruitTarget public Container ExplodingFruitTarget
{ {
@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Catch.UI
if (result.IsHit && fruit.CanBePlated) if (result.IsHit && fruit.CanBePlated)
{ {
var caughtFruit = (DrawableCatchHitObject)GetVisualRepresentation?.Invoke(fruit.HitObject); var caughtFruit = (DrawableCatchHitObject)CreateDrawableRepresentation?.Invoke(fruit.HitObject);
if (caughtFruit == null) return; if (caughtFruit == null) return;

View File

@ -34,13 +34,13 @@ namespace osu.Game.Rulesets.Catch.UI
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay); protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty, GetVisualRepresentation); protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty, CreateDrawableRepresentation);
protected override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new CatchPlayfieldAdjustmentContainer(); protected override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new CatchPlayfieldAdjustmentContainer();
protected override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo); protected override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
public override DrawableHitObject<CatchHitObject> GetVisualRepresentation(CatchHitObject h) public override DrawableHitObject<CatchHitObject> CreateDrawableRepresentation(CatchHitObject h)
{ {
switch (h) switch (h)
{ {
@ -49,9 +49,9 @@ namespace osu.Game.Rulesets.Catch.UI
case Fruit fruit: case Fruit fruit:
return new DrawableFruit(fruit); return new DrawableFruit(fruit);
case JuiceStream stream: case JuiceStream stream:
return new DrawableJuiceStream(stream, GetVisualRepresentation); return new DrawableJuiceStream(stream, CreateDrawableRepresentation);
case BananaShower shower: case BananaShower shower:
return new DrawableBananaShower(shower, GetVisualRepresentation); return new DrawableBananaShower(shower, CreateDrawableRepresentation);
case TinyDroplet tiny: case TinyDroplet tiny:
return new DrawableTinyDroplet(tiny); return new DrawableTinyDroplet(tiny);
case Droplet droplet: case Droplet droplet:

View File

@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Mania.UI
protected override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, Variant); protected override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, Variant);
public override DrawableHitObject<ManiaHitObject> GetVisualRepresentation(ManiaHitObject h) public override DrawableHitObject<ManiaHitObject> CreateDrawableRepresentation(ManiaHitObject h)
{ {
switch (h) switch (h)
{ {

View File

@ -1,4 +1,4 @@
// 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 System.Linq;
@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.UI
protected override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new OsuPlayfieldAdjustmentContainer(); protected override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new OsuPlayfieldAdjustmentContainer();
public override DrawableHitObject<OsuHitObject> GetVisualRepresentation(OsuHitObject h) public override DrawableHitObject<OsuHitObject> CreateDrawableRepresentation(OsuHitObject h)
{ {
switch (h) switch (h)
{ {

View File

@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Taiko.UI
protected override Playfield CreatePlayfield() => new TaikoPlayfield(Beatmap.ControlPointInfo); protected override Playfield CreatePlayfield() => new TaikoPlayfield(Beatmap.ControlPointInfo);
public override DrawableHitObject<TaikoHitObject> GetVisualRepresentation(TaikoHitObject h) public override DrawableHitObject<TaikoHitObject> CreateDrawableRepresentation(TaikoHitObject h)
{ {
switch (h) switch (h)
{ {

View File

@ -29,28 +29,28 @@ namespace osu.Game.Tests.Beatmaps.Formats
StoryboardLayer background = storyboard.Layers.FirstOrDefault(l => l.Depth == 3); StoryboardLayer background = storyboard.Layers.FirstOrDefault(l => l.Depth == 3);
Assert.IsNotNull(background); Assert.IsNotNull(background);
Assert.AreEqual(16, background.Elements.Count()); Assert.AreEqual(16, background.Elements.Count);
Assert.IsTrue(background.EnabledWhenFailing); Assert.IsTrue(background.EnabledWhenFailing);
Assert.IsTrue(background.EnabledWhenPassing); Assert.IsTrue(background.EnabledWhenPassing);
Assert.AreEqual("Background", background.Name); Assert.AreEqual("Background", background.Name);
StoryboardLayer fail = storyboard.Layers.FirstOrDefault(l => l.Depth == 2); StoryboardLayer fail = storyboard.Layers.FirstOrDefault(l => l.Depth == 2);
Assert.IsNotNull(fail); Assert.IsNotNull(fail);
Assert.AreEqual(0, fail.Elements.Count()); Assert.AreEqual(0, fail.Elements.Count);
Assert.IsTrue(fail.EnabledWhenFailing); Assert.IsTrue(fail.EnabledWhenFailing);
Assert.IsFalse(fail.EnabledWhenPassing); Assert.IsFalse(fail.EnabledWhenPassing);
Assert.AreEqual("Fail", fail.Name); Assert.AreEqual("Fail", fail.Name);
StoryboardLayer pass = storyboard.Layers.FirstOrDefault(l => l.Depth == 1); StoryboardLayer pass = storyboard.Layers.FirstOrDefault(l => l.Depth == 1);
Assert.IsNotNull(pass); Assert.IsNotNull(pass);
Assert.AreEqual(0, pass.Elements.Count()); Assert.AreEqual(0, pass.Elements.Count);
Assert.IsFalse(pass.EnabledWhenFailing); Assert.IsFalse(pass.EnabledWhenFailing);
Assert.IsTrue(pass.EnabledWhenPassing); Assert.IsTrue(pass.EnabledWhenPassing);
Assert.AreEqual("Pass", pass.Name); Assert.AreEqual("Pass", pass.Name);
StoryboardLayer foreground = storyboard.Layers.FirstOrDefault(l => l.Depth == 0); StoryboardLayer foreground = storyboard.Layers.FirstOrDefault(l => l.Depth == 0);
Assert.IsNotNull(foreground); Assert.IsNotNull(foreground);
Assert.AreEqual(151, foreground.Elements.Count()); Assert.AreEqual(151, foreground.Elements.Count);
Assert.IsTrue(foreground.EnabledWhenFailing); Assert.IsTrue(foreground.EnabledWhenFailing);
Assert.IsTrue(foreground.EnabledWhenPassing); Assert.IsTrue(foreground.EnabledWhenPassing);
Assert.AreEqual("Foreground", foreground.Name); Assert.AreEqual("Foreground", foreground.Name);
@ -62,7 +62,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.AreEqual(15, spriteCount); Assert.AreEqual(15, spriteCount);
Assert.AreEqual(1, animationCount); Assert.AreEqual(1, animationCount);
Assert.AreEqual(0, sampleCount); Assert.AreEqual(0, sampleCount);
Assert.AreEqual(background.Elements.Count(), spriteCount + animationCount + sampleCount); Assert.AreEqual(background.Elements.Count, spriteCount + animationCount + sampleCount);
var sprite = background.Elements.ElementAt(0) as StoryboardSprite; var sprite = background.Elements.ElementAt(0) as StoryboardSprite;
Assert.NotNull(sprite); Assert.NotNull(sprite);
@ -70,9 +70,9 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.AreEqual(new Vector2(320, 240), sprite.InitialPosition); Assert.AreEqual(new Vector2(320, 240), sprite.InitialPosition);
Assert.IsTrue(sprite.IsDrawable); Assert.IsTrue(sprite.IsDrawable);
Assert.AreEqual(Anchor.Centre, sprite.Origin); Assert.AreEqual(Anchor.Centre, sprite.Origin);
Assert.AreEqual("SB/lyric/ja-21.png", sprite.Path); Assert.AreEqual("SB/black.jpg", sprite.Path);
var animation = background.Elements.ElementAt(12) as StoryboardAnimation; var animation = background.Elements.OfType<StoryboardAnimation>().First();
Assert.NotNull(animation); Assert.NotNull(animation);
Assert.AreEqual(141175, animation.EndTime); Assert.AreEqual(141175, animation.EndTime);
Assert.AreEqual(10, animation.FrameCount); Assert.AreEqual(10, animation.FrameCount);

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -38,6 +39,10 @@ namespace osu.Game.Beatmaps.Formats
{ {
this.storyboard = storyboard; this.storyboard = storyboard;
base.ParseStreamInto(stream, storyboard); base.ParseStreamInto(stream, storyboard);
// OrderBy is used to guarantee that the parsing order of elements with equal start times is maintained (stably-sorted)
foreach (StoryboardLayer layer in storyboard.Layers)
layer.Elements = layer.Elements.OrderBy(h => h.StartTime).ToList();
} }
protected override void ParseLine(Storyboard storyboard, Section section, string line) protected override void ParseLine(Storyboard storyboard, Section section, string line)

View File

@ -15,7 +15,6 @@ using osu.Framework.Allocation;
using osu.Game.Overlays.Toolbar; using osu.Game.Overlays.Toolbar;
using osu.Game.Screens; using osu.Game.Screens;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
using osuTK;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -442,7 +441,7 @@ namespace osu.Game
loadComponentSingleFile(musicController = new MusicController loadComponentSingleFile(musicController = new MusicController
{ {
Position = new Vector2(0, Toolbar.HEIGHT), GetToolbarHeight = () => ToolbarOffset,
Anchor = Anchor.TopRight, Anchor = Anchor.TopRight,
Origin = Anchor.TopRight, Origin = Anchor.TopRight,
}, floatingOverlayContent.Add); }, floatingOverlayContent.Add);

View File

@ -56,6 +56,11 @@ namespace osu.Game.Overlays
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>(); private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
/// <summary>
/// Provide a source for the toolbar height.
/// </summary>
public Func<float> GetToolbarHeight;
public MusicController() public MusicController()
{ {
Width = 400; Width = 400;
@ -244,6 +249,8 @@ namespace osu.Game.Overlays
{ {
base.UpdateAfterChildren(); base.UpdateAfterChildren();
Height = dragContainer.Height; Height = dragContainer.Height;
dragContainer.Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 };
} }
protected override void Update() protected override void Update()

View File

@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.Edit
processor?.PostProcess(); processor?.PostProcess();
// Add visual representation // Add visual representation
var drawableObject = drawableRuleset.GetVisualRepresentation(tObject); var drawableObject = drawableRuleset.CreateDrawableRepresentation(tObject);
drawableRuleset.Playfield.Add(drawableObject); drawableRuleset.Playfield.Add(drawableObject);
drawableRuleset.Playfield.PostProcess(); drawableRuleset.Playfield.PostProcess();

View File

@ -161,7 +161,7 @@ namespace osu.Game.Rulesets.UI
private void loadObjects() private void loadObjects()
{ {
foreach (TObject h in Beatmap.HitObjects) foreach (TObject h in Beatmap.HitObjects)
addRepresentation(h); addHitObject(h);
Playfield.PostProcess(); Playfield.PostProcess();
@ -175,9 +175,9 @@ namespace osu.Game.Rulesets.UI
/// Creates and adds the visual representation of a <see cref="TObject"/> to this <see cref="DrawableRuleset{TObject}"/>. /// Creates and adds the visual representation of a <see cref="TObject"/> to this <see cref="DrawableRuleset{TObject}"/>.
/// </summary> /// </summary>
/// <param name="hitObject">The <see cref="TObject"/> to add the visual representation for.</param> /// <param name="hitObject">The <see cref="TObject"/> to add the visual representation for.</param>
private void addRepresentation(TObject hitObject) private void addHitObject(TObject hitObject)
{ {
var drawableObject = GetVisualRepresentation(hitObject); var drawableObject = CreateDrawableRepresentation(hitObject);
if (drawableObject == null) if (drawableObject == null)
return; return;
@ -209,7 +209,7 @@ namespace osu.Game.Rulesets.UI
/// </summary> /// </summary>
/// <param name="h">The HitObject to make drawable.</param> /// <param name="h">The HitObject to make drawable.</param>
/// <returns>The DrawableHitObject.</returns> /// <returns>The DrawableHitObject.</returns>
public abstract DrawableHitObject<TObject> GetVisualRepresentation(TObject h); public abstract DrawableHitObject<TObject> CreateDrawableRepresentation(TObject h);
public void Attach(KeyCounterDisplay keyCounter) => public void Attach(KeyCounterDisplay keyCounter) =>
(KeyBindingInputManager as ICanAttachKeyCounter)?.Attach(keyCounter); (KeyBindingInputManager as ICanAttachKeyCounter)?.Attach(keyCounter);

View File

@ -25,7 +25,7 @@ namespace osu.Game.Storyboards.Drawables
public DrawableStoryboardSample(StoryboardSample sample) public DrawableStoryboardSample(StoryboardSample sample)
{ {
this.sample = sample; this.sample = sample;
LifetimeStart = sample.Time; LifetimeStart = sample.StartTime;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -43,27 +43,27 @@ namespace osu.Game.Storyboards.Drawables
base.Update(); base.Update();
// TODO: this logic will need to be consolidated with other game samples like hit sounds. // TODO: this logic will need to be consolidated with other game samples like hit sounds.
if (Time.Current < sample.Time) if (Time.Current < sample.StartTime)
{ {
// We've rewound before the start time of the sample // We've rewound before the start time of the sample
channel?.Stop(); channel?.Stop();
// In the case that the user fast-forwards to a point far beyond the start time of the sample, // In the case that the user fast-forwards to a point far beyond the start time of the sample,
// we want to be able to fall into the if-conditional below (therefore we must not have a life time end) // we want to be able to fall into the if-conditional below (therefore we must not have a life time end)
LifetimeStart = sample.Time; LifetimeStart = sample.StartTime;
LifetimeEnd = double.MaxValue; LifetimeEnd = double.MaxValue;
} }
else if (Time.Current - Time.Elapsed < sample.Time) else if (Time.Current - Time.Elapsed < sample.StartTime)
{ {
// We've passed the start time of the sample. We only play the sample if we're within an allowable range // We've passed the start time of the sample. We only play the sample if we're within an allowable range
// from the sample's start, to reduce layering if we've been fast-forwarded far into the future // from the sample's start, to reduce layering if we've been fast-forwarded far into the future
if (Time.Current - sample.Time < allowable_late_start) if (Time.Current - sample.StartTime < allowable_late_start)
channel?.Play(); channel?.Play();
// In the case that the user rewinds to a point far behind the start time of the sample, // In the case that the user rewinds to a point far behind the start time of the sample,
// we want to be able to fall into the if-conditional above (therefore we must not have a life time start) // we want to be able to fall into the if-conditional above (therefore we must not have a life time start)
LifetimeStart = double.MinValue; LifetimeStart = double.MinValue;
LifetimeEnd = sample.Time; LifetimeEnd = sample.StartTime;
} }
} }
} }

View File

@ -10,6 +10,8 @@ namespace osu.Game.Storyboards
string Path { get; } string Path { get; }
bool IsDrawable { get; } bool IsDrawable { get; }
double StartTime { get; }
Drawable CreateDrawable(); Drawable CreateDrawable();
} }
} }

View File

@ -13,8 +13,7 @@ namespace osu.Game.Storyboards
public bool EnabledWhenPassing = true; public bool EnabledWhenPassing = true;
public bool EnabledWhenFailing = true; public bool EnabledWhenFailing = true;
private readonly List<IStoryboardElement> elements = new List<IStoryboardElement>(); public List<IStoryboardElement> Elements = new List<IStoryboardElement>();
public IEnumerable<IStoryboardElement> Elements => elements;
public StoryboardLayer(string name, int depth) public StoryboardLayer(string name, int depth)
{ {
@ -24,7 +23,7 @@ namespace osu.Game.Storyboards
public void Add(IStoryboardElement element) public void Add(IStoryboardElement element)
{ {
elements.Add(element); Elements.Add(element);
} }
public DrawableStoryboardLayer CreateDrawable() public DrawableStoryboardLayer CreateDrawable()

View File

@ -11,13 +11,14 @@ namespace osu.Game.Storyboards
public string Path { get; set; } public string Path { get; set; }
public bool IsDrawable => true; public bool IsDrawable => true;
public double Time; public double StartTime { get; }
public float Volume; public float Volume;
public StoryboardSample(string path, double time, float volume) public StoryboardSample(string path, double time, float volume)
{ {
Path = path; Path = path;
Time = time; StartTime = time;
Volume = volume; Volume = volume;
} }