1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-13 01:33:10 +08:00

Merge branch 'master' into fix-taiko-proxies

This commit is contained in:
Dean Herbert 2018-06-17 19:38:52 +09:00 committed by GitHub
commit 479eac8aa8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 301 additions and 28 deletions

View File

@ -19,7 +19,7 @@ namespace osu.Game.Tests.Beatmaps.IO
[TestFixture]
public class ImportBeatmapTest
{
private const string osz_path = @"../../../../osu-resources/osu.Game.Resources/Beatmaps/241526 Soleily - Renatus.osz";
public const string TEST_OSZ_PATH = @"../../../../osu-resources/osu.Game.Resources/Beatmaps/241526 Soleily - Renatus.osz";
[Test]
public void TestImportWhenClosed()
@ -265,7 +265,7 @@ namespace osu.Game.Tests.Beatmaps.IO
private string createTemporaryBeatmap()
{
var temp = Path.GetTempFileName() + ".osz";
File.Copy(osz_path, temp, true);
File.Copy(TEST_OSZ_PATH, temp, true);
Assert.IsTrue(File.Exists(temp));
return temp;
}

View File

@ -4,28 +4,42 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Overlays;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Screens.Edit.Screens.Compose.Timeline;
using OpenTK.Graphics;
namespace osu.Game.Tests.Visual
{
[TestFixture]
public class TestCaseEditorComposeTimeline : OsuTestCase
public class TestCaseEditorComposeTimeline : EditorClockTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(TimelineArea), typeof(Timeline), typeof(TimelineButton) };
public TestCaseEditorComposeTimeline()
[BackgroundDependencyLoader]
private void load()
{
Beatmap.Value = new WaveformTestBeatmap();
Children = new Drawable[]
{
new MusicController
new FillFlowContainer
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
State = Visibility.Visible
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 5),
Children = new Drawable[]
{
new StartStopButton(),
new AudioVisualiser(),
}
},
new TimelineArea
{
@ -36,5 +50,85 @@ namespace osu.Game.Tests.Visual
}
};
}
private class AudioVisualiser : CompositeDrawable
{
private readonly Drawable marker;
private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
private IAdjustableClock adjustableClock;
public AudioVisualiser()
{
Size = new Vector2(250, 25);
InternalChildren = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0.25f,
},
marker = new Box
{
RelativePositionAxes = Axes.X,
RelativeSizeAxes = Axes.Y,
Width = 2,
}
};
}
[BackgroundDependencyLoader]
private void load(IAdjustableClock adjustableClock, IBindableBeatmap beatmap)
{
this.adjustableClock = adjustableClock;
this.beatmap.BindTo(beatmap);
}
protected override void Update()
{
base.Update();
if (beatmap.Value.Track.IsLoaded)
marker.X = (float)(adjustableClock.CurrentTime / beatmap.Value.Track.Length);
}
}
private class StartStopButton : Button
{
private IAdjustableClock adjustableClock;
private bool started;
public StartStopButton()
{
BackgroundColour = Color4.SlateGray;
Size = new Vector2(100, 50);
Text = "Start";
Action = onClick;
}
[BackgroundDependencyLoader]
private void load(IAdjustableClock adjustableClock)
{
this.adjustableClock = adjustableClock;
}
private void onClick()
{
if (started)
{
adjustableClock.Stop();
Text = "Start";
}
else
{
adjustableClock.Start();
Text = "Stop";
}
started = !started;
}
}
}
}

View File

@ -10,7 +10,6 @@ using osu.Framework.Graphics.Audio;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays;
namespace osu.Game.Tests.Visual
{
@ -20,22 +19,14 @@ namespace osu.Game.Tests.Visual
[BackgroundDependencyLoader]
private void load()
{
Beatmap.Value = new WaveformTestBeatmap();
FillFlowContainer flow;
Child = flow = new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 10),
Children = new Drawable[]
{
new MusicController
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Y = 100,
State = Visibility.Visible
},
}
};
for (int i = 1; i <= 16; i *= 2)
@ -44,10 +35,9 @@ namespace osu.Game.Tests.Visual
{
RelativeSizeAxes = Axes.Both,
Resolution = 1f / i,
Waveform = Beatmap.Value.Waveform,
};
Beatmap.ValueChanged += b => newDisplay.Waveform = b.Waveform;
flow.Add(new Container
{
RelativeSizeAxes = Axes.X,

View File

@ -0,0 +1,55 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.IO;
using System.Linq;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats;
using osu.Game.IO.Archives;
using osu.Game.Tests.Beatmaps.IO;
namespace osu.Game.Tests
{
/// <summary>
/// A <see cref="WorkingBeatmap"/> that is used for testcases that include waveforms.
/// </summary>
public class WaveformTestBeatmap : WorkingBeatmap
{
private readonly ZipArchiveReader reader;
private readonly FileStream stream;
public WaveformTestBeatmap()
: base(new BeatmapInfo())
{
stream = File.OpenRead(ImportBeatmapTest.TEST_OSZ_PATH);
reader = new ZipArchiveReader(stream);
}
public override void Dispose()
{
base.Dispose();
stream?.Dispose();
reader?.Dispose();
}
protected override IBeatmap GetBeatmap() => createTestBeatmap();
protected override Texture GetBackground() => null;
protected override Waveform GetWaveform() => new Waveform(getAudioStream());
protected override Track GetTrack() => new TrackBass(getAudioStream());
private Stream getAudioStream() => reader.GetStream(reader.Filenames.First(f => f.EndsWith(".mp3")));
private Stream getBeatmapStream() => reader.GetStream(reader.Filenames.First(f => f.EndsWith(".osu")));
private Beatmap createTestBeatmap()
{
using (var beatmapStream = getBeatmapStream())
using (var beatmapReader = new StreamReader(beatmapStream))
return Decoder.GetDecoder<Beatmap>(beatmapReader).Decode(beatmapReader);
}
}
}

View File

@ -2,9 +2,12 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Audio;
using osu.Framework.Input;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
@ -15,6 +18,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
public readonly Bindable<bool> WaveformVisible = new Bindable<bool>();
public readonly IBindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
private IAdjustableClock adjustableClock;
public Timeline()
{
ZoomDuration = 200;
@ -25,8 +30,10 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
private WaveformGraph waveform;
[BackgroundDependencyLoader]
private void load(IBindableBeatmap beatmap)
private void load(IBindableBeatmap beatmap, IAdjustableClock adjustableClock)
{
this.adjustableClock = adjustableClock;
Child = waveform = new WaveformGraph
{
RelativeSizeAxes = Axes.Both,
@ -46,12 +53,132 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
waveform.Waveform = Beatmap.Value.Waveform;
}
/// <summary>
/// The track's time in the previous frame.
/// </summary>
private double lastTrackTime;
/// <summary>
/// Whether the user is currently dragging the timeline.
/// </summary>
private bool handlingDragInput;
/// <summary>
/// Whether the track was playing before a user drag event.
/// </summary>
private bool trackWasPlaying;
protected override void Update()
{
base.Update();
// We want time = 0 to be at the centre of the container when scrolled to the start
// The extrema of track time should be positioned at the centre of the container when scrolled to the start or end
Content.Margin = new MarginPadding { Horizontal = DrawWidth / 2 };
if (handlingDragInput)
{
// The user is dragging - the track should always follow the timeline
seekTrackToCurrent();
}
else if (adjustableClock.IsRunning)
{
// If the user hasn't provided mouse input but the track is running, always follow the track
scrollToTrackTime();
}
else
{
// The track isn't playing, so we want to smooth-scroll once more, and re-enable wheel scrolling
// There are two cases we have to be wary of:
// 1) The user scrolls on this timeline: We want the track to follow us
// 2) The user changes the track time through some other means (scrolling in the editor or overview timeline): We want to follow the track time
// The simplest way to cover both cases is by checking that inter-frame track times are identical
if (adjustableClock.CurrentTime == lastTrackTime)
{
// The track hasn't been seeked externally
seekTrackToCurrent();
}
else
{
// The track has been seeked externally
scrollToTrackTime();
}
}
lastTrackTime = adjustableClock.CurrentTime;
void seekTrackToCurrent()
{
if (!(Beatmap.Value.Track is TrackVirtual))
adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length);
}
void scrollToTrackTime()
{
if (!(Beatmap.Value.Track is TrackVirtual))
ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false);
}
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
if (base.OnMouseDown(state, args))
{
beginUserDrag();
return true;
}
return false;
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
endUserDrag();
return base.OnMouseUp(state, args);
}
private void beginUserDrag()
{
handlingDragInput = true;
trackWasPlaying = adjustableClock.IsRunning;
adjustableClock.Stop();
}
private void endUserDrag()
{
handlingDragInput = false;
if (trackWasPlaying)
adjustableClock.Start();
}
protected override ScrollbarContainer CreateScrollbar(Direction direction) => new TimelineScrollbar(this, direction);
private class TimelineScrollbar : ScrollbarContainer
{
private readonly Timeline timeline;
public TimelineScrollbar(Timeline timeline, Direction scrollDir)
: base(scrollDir)
{
this.timeline = timeline;
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
if (base.OnMouseDown(state, args))
{
timeline.beginUserDrag();
return true;
}
return false;
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
timeline.endUserDrag();
return base.OnMouseUp(state, args);
}
}
}
}

View File

@ -25,13 +25,20 @@ namespace osu.Game.Tests.Visual
Clock = new EditorClock(new ControlPointInfo(), 5000, BeatDivisor) { IsCoupled = false };
}
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
dependencies.Cache(BeatDivisor);
dependencies.CacheAs<IFrameBasedClock>(Clock);
dependencies.CacheAs<IAdjustableClock>(Clock);
return dependencies;
}
[BackgroundDependencyLoader]
private void load()
{
Dependencies.Cache(BeatDivisor);
Dependencies.CacheAs<IFrameBasedClock>(Clock);
Dependencies.CacheAs<IAdjustableClock>(Clock);
Beatmap.BindValueChanged(beatmapChanged, true);
}