1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-21 22:07:25 +08:00

Merge remote-tracking branch 'upstream/master' into relative-beat-lengths

This commit is contained in:
Dean Herbert 2019-08-28 20:21:56 +09:00
commit ecfcbe3723
46 changed files with 386 additions and 402 deletions

View File

@ -61,6 +61,6 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.823.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.823.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.828.0" />
</ItemGroup>
</Project>

View File

@ -15,6 +15,7 @@ using osu.Framework.Graphics.Sprites;
using osuTK.Graphics;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics.Textures;
using osu.Game.Audio;
namespace osu.Game.Rulesets.Catch.Tests
{
@ -92,7 +93,7 @@ namespace osu.Game.Rulesets.Catch.Tests
return null;
}
public SampleChannel GetSample(string sampleName) =>
public SampleChannel GetSample(ISampleInfo sampleInfo) =>
throw new NotImplementedException();
public Texture GetTexture(string componentName) =>

View File

@ -58,14 +58,12 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
ApplyResult(r => r.Type = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss);
}
protected override bool UseTransformStateManagement => false;
protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt;
protected override void UpdateState(ArmedState state)
protected override void UpdateInitialTransforms() => this.FadeIn(200);
protected override void UpdateStateTransforms(ArmedState state)
{
// TODO: update to use new state management.
using (BeginAbsoluteSequence(HitObject.StartTime - HitObject.TimePreempt))
this.FadeIn(200);
var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
using (BeginAbsoluteSequence(endTime, true))

View File

@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Catch.UI
if (lastPlateableFruit == null)
return;
// this is required to make this run after the last caught fruit runs UpdateState at least once.
// this is required to make this run after the last caught fruit runs updateState() at least once.
// TODO: find a better alternative
if (lastPlateableFruit.IsLoaded)
action();

View File

@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
Alpha = 0.2f;
}
protected override void UpdateState(ArmedState state)
protected override void UpdateStateTransforms(ArmedState state)
{
}
}

View File

@ -8,6 +8,7 @@ using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI.Scrolling;
@ -104,6 +105,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
bodyPiece.Height = DrawHeight - Head.Height / 2 + Tail.Height / 2;
}
protected override void UpdateStateTransforms(ArmedState state)
{
using (BeginDelayedSequence(HitObject.Duration, true))
base.UpdateStateTransforms(state);
}
protected void BeginHold()
{
holdStartTime = Time.Current;

View File

@ -45,24 +45,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
Anchor = Origin = e.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
}
}
public abstract class DrawableManiaHitObject<TObject> : DrawableManiaHitObject
where TObject : ManiaHitObject
{
public new readonly TObject HitObject;
protected override void UpdateInitialTransforms() => this.FadeIn();
protected DrawableManiaHitObject(TObject hitObject)
: base(hitObject)
protected override void UpdateStateTransforms(ArmedState state)
{
HitObject = hitObject;
}
protected override bool UseTransformStateManagement => false;
protected override void UpdateState(ArmedState state)
{
// TODO: update to use new state management.
switch (state)
{
case ArmedState.Miss:
@ -75,4 +62,16 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
}
}
}
public abstract class DrawableManiaHitObject<TObject> : DrawableManiaHitObject
where TObject : ManiaHitObject
{
public new readonly TObject HitObject;
protected DrawableManiaHitObject(TObject hitObject)
: base(hitObject)
{
HitObject = hitObject;
}
}
}

View File

@ -247,10 +247,6 @@ namespace osu.Game.Rulesets.Taiko.Tests
: base(hitObject)
{
}
protected override void UpdateState(ArmedState state)
{
}
}
}
}

View File

@ -53,9 +53,5 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
Alpha = 0.75f
});
}
protected override void UpdateState(ArmedState state)
{
}
}
}

View File

@ -88,13 +88,13 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
ApplyResult(r => r.Type = HitResult.Miss);
}
protected override void UpdateState(ArmedState state)
protected override void UpdateStateTransforms(ArmedState state)
{
switch (state)
{
case ArmedState.Hit:
case ArmedState.Miss:
this.FadeOut(100).Expire();
this.Delay(HitObject.Duration).FadeOut(100).Expire();
break;
}
}

View File

@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
ApplyResult(r => r.Type = HitResult.Great);
}
protected override void UpdateState(ArmedState state)
protected override void UpdateStateTransforms(ArmedState state)
{
switch (state)
{

View File

@ -92,56 +92,42 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
Size = BaseSize * Parent.RelativeChildSize;
}
protected override void UpdateState(ArmedState state)
protected override void UpdateStateTransforms(ArmedState state)
{
// TODO: update to use new state management.
var circlePiece = MainPiece as CirclePiece;
circlePiece?.FlashBox.FinishTransforms();
var offset = !AllJudged ? 0 : Time.Current - HitObject.StartTime;
using (BeginDelayedSequence(HitObject.StartTime - Time.Current + offset, true))
switch (state)
{
switch (State.Value)
{
case ArmedState.Idle:
validActionPressed = false;
case ArmedState.Idle:
validActionPressed = false;
UnproxyContent();
this.Delay(HitObject.HitWindows.HalfWindowFor(HitResult.Miss)).Expire();
break;
UnproxyContent();
this.Delay(HitObject.HitWindows.HalfWindowFor(HitResult.Miss)).Expire();
break;
case ArmedState.Miss:
this.FadeOut(100)
.Expire();
break;
case ArmedState.Miss:
this.FadeOut(100)
.Expire();
break;
case ArmedState.Hit:
// If we're far enough away from the left stage, we should bring outselves in front of it
ProxyContent();
case ArmedState.Hit:
// If we're far enough away from the left stage, we should bring outselves in front of it
ProxyContent();
var flash = circlePiece?.FlashBox;
var flash = (MainPiece as CirclePiece)?.FlashBox;
flash?.FadeTo(0.9f).FadeOut(300);
if (flash != null)
{
flash.FadeTo(0.9f);
flash.FadeOut(300);
}
const float gravity_time = 300;
const float gravity_travel_height = 200;
const float gravity_time = 300;
const float gravity_travel_height = 200;
this.ScaleTo(0.8f, gravity_time * 2, Easing.OutQuad);
this.ScaleTo(0.8f, gravity_time * 2, Easing.OutQuad);
this.MoveToY(-gravity_travel_height, gravity_time, Easing.Out)
.Then()
.MoveToY(gravity_travel_height * 2, gravity_time * 2, Easing.In);
this.MoveToY(-gravity_travel_height, gravity_time, Easing.Out)
.Then()
.MoveToY(gravity_travel_height * 2, gravity_time * 2, Easing.In);
this.FadeOut(800)
.Expire();
this.FadeOut(800)
.Expire();
break;
}
break;
}
}

View File

@ -18,9 +18,5 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
MainObject = mainObject;
}
protected override void UpdateState(ArmedState state)
{
}
}
}

View File

@ -25,6 +25,11 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
private const float target_ring_scale = 5f;
private const float inner_ring_alpha = 0.65f;
/// <summary>
/// Offset away from the start time of the swell at which the ring starts appearing.
/// </summary>
private const double ring_appear_offset = 100;
private readonly List<DrawableSwellTick> ticks = new List<DrawableSwellTick>();
private readonly Container bodyContainer;
@ -179,26 +184,34 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
}
}
protected override void UpdateState(ArmedState state)
protected override void UpdateInitialTransforms()
{
const float preempt = 100;
const float out_transition_time = 300;
base.UpdateInitialTransforms();
using (BeginAbsoluteSequence(HitObject.StartTime - ring_appear_offset, true))
targetRing.ScaleTo(target_ring_scale, 400, Easing.OutQuint);
}
protected override void UpdateStateTransforms(ArmedState state)
{
const double transition_duration = 300;
switch (state)
{
case ArmedState.Idle:
UnproxyContent();
expandingRing.FadeTo(0);
using (BeginAbsoluteSequence(HitObject.StartTime - preempt, true))
targetRing.ScaleTo(target_ring_scale, preempt * 4, Easing.OutQuint);
break;
case ArmedState.Miss:
case ArmedState.Hit:
this.FadeOut(out_transition_time, Easing.Out);
bodyContainer.ScaleTo(1.4f, out_transition_time);
using (BeginAbsoluteSequence(Time.Current, true))
{
this.FadeOut(transition_duration, Easing.Out);
bodyContainer.ScaleTo(1.4f, transition_duration);
Expire();
}
Expire();
break;
}
}
@ -212,9 +225,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
// Make the swell stop at the hit target
X = Math.Max(0, X);
double t = Math.Min(HitObject.StartTime, Time.Current);
if (t == HitObject.StartTime)
if (Time.Current >= HitObject.StartTime - ring_appear_offset)
ProxyContent();
else
UnproxyContent();
}
private bool? lastWasCentre;

View File

@ -1,7 +1,6 @@
// 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.
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
@ -21,10 +20,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
}
protected override void UpdateState(ArmedState state)
{
}
public override bool OnPressed(TaikoAction action) => false;
}
}

View File

@ -78,10 +78,31 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
public abstract bool OnPressed(TaikoAction action);
public virtual bool OnReleased(TaikoAction action) => false;
protected override void UpdateInitialTransforms() => this.FadeIn();
public override double LifetimeStart
{
get => base.LifetimeStart;
set
{
base.LifetimeStart = value;
proxiedContent.LifetimeStart = value;
}
}
public override double LifetimeEnd
{
get => base.LifetimeEnd;
set
{
base.LifetimeEnd = value;
proxiedContent.LifetimeEnd = value;
}
}
private class ProxiedContentContainer : Container
{
public override double LifetimeStart => Parent?.LifetimeStart ?? base.LifetimeStart;
public override double LifetimeEnd => Parent?.LifetimeEnd ?? base.LifetimeEnd;
public override bool RemoveWhenNotAlive => false;
}
}
@ -121,8 +142,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
}
}
protected override bool UseTransformStateManagement => false;
// Normal and clap samples are handled by the drum
protected override IEnumerable<HitSampleInfo> GetSamples() => HitObject.Samples.Where(s => s.Name != HitSampleInfo.HIT_NORMAL && s.Name != HitSampleInfo.HIT_CLAP);

View File

@ -44,9 +44,8 @@ namespace osu.Game.Rulesets.Taiko.UI
private readonly JudgementContainer<DrawableTaikoJudgement> judgementContainer;
internal readonly HitTarget HitTarget;
private readonly Container topLevelHitContainer;
private readonly Container barlineContainer;
private readonly ProxyContainer topLevelHitContainer;
private readonly ProxyContainer barlineContainer;
private readonly Container overlayBackgroundContainer;
private readonly Container backgroundContainer;
@ -108,7 +107,7 @@ namespace osu.Game.Rulesets.Taiko.UI
}
}
},
barlineContainer = new Container
barlineContainer = new ProxyContainer
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = HIT_TARGET_OFFSET }
@ -183,7 +182,7 @@ namespace osu.Game.Rulesets.Taiko.UI
}
}
},
topLevelHitContainer = new Container
topLevelHitContainer = new ProxyContainer
{
Name = "Top level hit objects",
RelativeSizeAxes = Axes.Both,
@ -256,5 +255,15 @@ namespace osu.Game.Rulesets.Taiko.UI
break;
}
}
private class ProxyContainer : LifetimeManagementContainer
{
public new MarginPadding Padding
{
set => base.Padding = value;
}
public void Add(Drawable proxy) => AddInternal(proxy);
}
}
}

View File

@ -58,7 +58,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
int spriteCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardSprite));
int animationCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardAnimation));
int sampleCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardSample));
int sampleCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardSampleInfo));
Assert.AreEqual(15, spriteCount);
Assert.AreEqual(1, animationCount);

View File

@ -200,10 +200,6 @@ namespace osu.Game.Tests.Visual.Gameplay
break;
}
}
protected override void UpdateState(ArmedState state)
{
}
}
private class TestDrawableHitObject : DrawableHitObject<HitObject>
@ -216,10 +212,6 @@ namespace osu.Game.Tests.Visual.Gameplay
AddInternal(new Box { Size = new Vector2(75) });
}
protected override void UpdateState(ArmedState state)
{
}
}
}
}

View File

@ -10,6 +10,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Textures;
using osu.Game.Audio;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Skinning;
@ -253,7 +254,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public Texture GetTexture(string componentName) => throw new NotImplementedException();
public SampleChannel GetSample(string sampleName) => throw new NotImplementedException();
public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration => throw new NotImplementedException();
}
@ -264,7 +265,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public Texture GetTexture(string componentName) => throw new NotImplementedException();
public SampleChannel GetSample(string sampleName) => throw new NotImplementedException();
public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration => throw new NotImplementedException();
}
@ -275,7 +276,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public Texture GetTexture(string componentName) => throw new NotImplementedException();
public SampleChannel GetSample(string sampleName) => throw new NotImplementedException();
public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration => throw new NotImplementedException();
}

View File

@ -15,6 +15,7 @@ using osu.Framework.MathUtils;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
@ -79,8 +80,12 @@ namespace osu.Game.Tests.Visual.SongSelect
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, defaultBeatmap = Beatmap.Default));
Beatmap.SetDefault();
Dependencies.Cache(config = new OsuConfigManager(LocalStorage));
}
private OsuConfigManager config;
[SetUp]
public virtual void SetUp() => Schedule(() =>
{
@ -111,13 +116,15 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap);
AddStep(@"Sort by Artist", delegate { songSelect.FilterControl.Sort = SortMode.Artist; });
AddStep(@"Sort by Title", delegate { songSelect.FilterControl.Sort = SortMode.Title; });
AddStep(@"Sort by Author", delegate { songSelect.FilterControl.Sort = SortMode.Author; });
AddStep(@"Sort by DateAdded", delegate { songSelect.FilterControl.Sort = SortMode.DateAdded; });
AddStep(@"Sort by BPM", delegate { songSelect.FilterControl.Sort = SortMode.BPM; });
AddStep(@"Sort by Length", delegate { songSelect.FilterControl.Sort = SortMode.Length; });
AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; });
var sortMode = config.GetBindable<SortMode>(OsuSetting.SongSelectSortingMode);
AddStep(@"Sort by Artist", delegate { sortMode.Value = SortMode.Artist; });
AddStep(@"Sort by Title", delegate { sortMode.Value = SortMode.Title; });
AddStep(@"Sort by Author", delegate { sortMode.Value = SortMode.Author; });
AddStep(@"Sort by DateAdded", delegate { sortMode.Value = SortMode.DateAdded; });
AddStep(@"Sort by BPM", delegate { sortMode.Value = SortMode.BPM; });
AddStep(@"Sort by Length", delegate { sortMode.Value = SortMode.Length; });
AddStep(@"Sort by Difficulty", delegate { sortMode.Value = SortMode.Difficulty; });
}
[Test]

View File

@ -121,7 +121,7 @@ namespace osu.Game.Beatmaps.Formats
var layer = parseLayer(split[2]);
var path = cleanFilename(split[3]);
var volume = split.Length > 4 ? float.Parse(split[4], CultureInfo.InvariantCulture) : 100;
storyboard.GetLayer(layer).Add(new StoryboardSample(path, time, volume));
storyboard.GetLayer(layer).Add(new StoryboardSampleInfo(path, time, (int)volume));
break;
}
}

View File

@ -8,6 +8,7 @@ using osu.Framework.Platform;
using osu.Game.Overlays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
namespace osu.Game.Configuration
{
@ -25,6 +26,9 @@ namespace osu.Game.Configuration
Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10, 0.1);
Set(OsuSetting.DisplayStarsMaximum, 10.0, 0, 10, 0.1);
Set(OsuSetting.SongSelectGroupingMode, GroupMode.All);
Set(OsuSetting.SongSelectSortingMode, SortMode.Title);
Set(OsuSetting.RandomSelectAlgorithm, RandomSelectAlgorithm.RandomPermutation);
Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1);
@ -150,6 +154,8 @@ namespace osu.Game.Configuration
SaveUsername,
DisplayStarsMinimum,
DisplayStarsMaximum,
SongSelectGroupingMode,
SongSelectSortingMode,
RandomSelectAlgorithm,
ShowFpsDisplay,
ChatDisplayHeight,

View File

@ -22,7 +22,7 @@ using SixLabors.ImageSharp;
namespace osu.Game.Graphics
{
public class ScreenshotManager : Container, IKeyBindingHandler<GlobalAction>, IHandleGlobalInput
public class ScreenshotManager : Container, IKeyBindingHandler<GlobalAction>, IHandleGlobalKeyboardInput
{
private readonly BindableBool cursorVisibility = new BindableBool(true);

View File

@ -10,7 +10,7 @@ using osu.Framework.Input.Bindings;
namespace osu.Game.Input.Bindings
{
public class GlobalActionContainer : DatabasedKeyBindingContainer<GlobalAction>, IHandleGlobalInput
public class GlobalActionContainer : DatabasedKeyBindingContainer<GlobalAction>, IHandleGlobalKeyboardInput
{
private readonly Drawable handler;

View File

@ -12,7 +12,7 @@ namespace osu.Game.Input
/// <summary>
/// Track whether the end-user is in an idle state, based on their last interaction with the game.
/// </summary>
public class IdleTracker : Component, IKeyBindingHandler<PlatformAction>, IHandleGlobalInput
public class IdleTracker : Component, IKeyBindingHandler<PlatformAction>, IHandleGlobalKeyboardInput
{
private readonly double timeToIdle;

View File

@ -1,21 +1,22 @@
// 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.
using System.Linq;
using System.Collections.Generic;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Direct;
using osu.Game.Users;
using osuTK;
namespace osu.Game.Overlays.Profile.Sections.Beatmaps
{
public class PaginatedBeatmapContainer : PaginatedContainer
public class PaginatedBeatmapContainer : PaginatedContainer<APIBeatmapSet>
{
private const float panel_padding = 10f;
private readonly BeatmapSetType type;
private GetUserBeatmapsRequest request;
public PaginatedBeatmapContainer(BeatmapSetType type, Bindable<User> user, string header, string missing = "None... yet.")
: base(user, header, missing)
@ -27,40 +28,15 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps
ItemsContainer.Spacing = new Vector2(panel_padding);
}
protected override void ShowMore()
{
request = new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
request.Success += sets => Schedule(() =>
protected override APIRequest<List<APIBeatmapSet>> CreateRequest() =>
new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
protected override Drawable CreateDrawableItem(APIBeatmapSet model) => !model.OnlineBeatmapSetID.HasValue
? null
: new DirectGridPanel(model.ToBeatmapSet(Rulesets))
{
MoreButton.FadeTo(sets.Count == ItemsPerPage ? 1 : 0);
MoreButton.IsLoading = false;
if (!sets.Any() && VisiblePages == 1)
{
MissingText.Show();
return;
}
foreach (var s in sets)
{
if (!s.OnlineBeatmapSetID.HasValue)
continue;
ItemsContainer.Add(new DirectGridPanel(s.ToBeatmapSet(Rulesets))
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
});
}
});
Api.Queue(request);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
request?.Cancel();
}
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
};
}
}

View File

@ -1,19 +1,19 @@
// 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.
using System.Linq;
using System.Collections.Generic;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Users;
namespace osu.Game.Overlays.Profile.Sections.Historical
{
public class PaginatedMostPlayedBeatmapContainer : PaginatedContainer
public class PaginatedMostPlayedBeatmapContainer : PaginatedContainer<APIUserMostPlayedBeatmap>
{
private GetUserMostPlayedBeatmapsRequest request;
public PaginatedMostPlayedBeatmapContainer(Bindable<User> user)
: base(user, "Most Played Beatmaps", "No records. :(")
{
@ -22,35 +22,10 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
ItemsContainer.Direction = FillDirection.Vertical;
}
protected override void ShowMore()
{
request = new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++, ItemsPerPage);
request.Success += beatmaps => Schedule(() =>
{
MoreButton.FadeTo(beatmaps.Count == ItemsPerPage ? 1 : 0);
MoreButton.IsLoading = false;
protected override APIRequest<List<APIUserMostPlayedBeatmap>> CreateRequest() =>
new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++, ItemsPerPage);
if (!beatmaps.Any() && VisiblePages == 1)
{
MissingText.Show();
return;
}
MissingText.Hide();
foreach (var beatmap in beatmaps)
{
ItemsContainer.Add(new DrawableMostPlayedBeatmap(beatmap.GetBeatmapInfo(Rulesets), beatmap.PlayCount));
}
});
Api.Queue(request);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
request?.Cancel();
}
protected override Drawable CreateDrawableItem(APIUserMostPlayedBeatmap model) =>
new DrawableMostPlayedBeatmap(model.GetBeatmapInfo(Rulesets), model.PlayCount);
}
}

View File

@ -11,22 +11,27 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Online.API;
using osu.Game.Rulesets;
using osu.Game.Users;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace osu.Game.Overlays.Profile.Sections
{
public abstract class PaginatedContainer : FillFlowContainer
public abstract class PaginatedContainer<TModel> : FillFlowContainer
{
protected readonly FillFlowContainer ItemsContainer;
protected readonly ShowMoreButton MoreButton;
protected readonly OsuSpriteText MissingText;
private readonly ShowMoreButton moreButton;
private readonly OsuSpriteText missingText;
private APIRequest<List<TModel>> retrievalRequest;
private CancellationTokenSource loadCancellation;
[Resolved]
private IAPIProvider api { get; set; }
protected int VisiblePages;
protected int ItemsPerPage;
protected readonly Bindable<User> User = new Bindable<User>();
protected IAPIProvider Api;
protected APIRequest RetrievalRequest;
protected readonly FillFlowContainer ItemsContainer;
protected RulesetStore Rulesets;
protected PaginatedContainer(Bindable<User> user, string header, string missing)
@ -51,15 +56,15 @@ namespace osu.Game.Overlays.Profile.Sections
RelativeSizeAxes = Axes.X,
Spacing = new Vector2(0, 2),
},
MoreButton = new ShowMoreButton
moreButton = new ShowMoreButton
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Alpha = 0,
Margin = new MarginPadding { Top = 10 },
Action = ShowMore,
Action = showMore,
},
MissingText = new OsuSpriteText
missingText = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 15),
Text = missing,
@ -69,9 +74,8 @@ namespace osu.Game.Overlays.Profile.Sections
}
[BackgroundDependencyLoader]
private void load(IAPIProvider api, RulesetStore rulesets)
private void load(RulesetStore rulesets)
{
Api = api;
Rulesets = rulesets;
User.ValueChanged += onUserChanged;
@ -80,13 +84,54 @@ namespace osu.Game.Overlays.Profile.Sections
private void onUserChanged(ValueChangedEvent<User> e)
{
loadCancellation?.Cancel();
retrievalRequest?.Cancel();
VisiblePages = 0;
ItemsContainer.Clear();
if (e.NewValue != null)
ShowMore();
showMore();
}
protected abstract void ShowMore();
private void showMore()
{
loadCancellation = new CancellationTokenSource();
retrievalRequest = CreateRequest();
retrievalRequest.Success += UpdateItems;
api.Queue(retrievalRequest);
}
protected virtual void UpdateItems(List<TModel> items) => Schedule(() =>
{
if (!items.Any() && VisiblePages == 1)
{
moreButton.Hide();
moreButton.IsLoading = false;
missingText.Show();
return;
}
LoadComponentsAsync(items.Select(CreateDrawableItem).Where(d => d != null), drawables =>
{
missingText.Hide();
moreButton.FadeTo(items.Count == ItemsPerPage ? 1 : 0);
moreButton.IsLoading = false;
ItemsContainer.AddRange(drawables);
}, loadCancellation.Token);
});
protected abstract APIRequest<List<TModel>> CreateRequest();
protected abstract Drawable CreateDrawableItem(TModel model);
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
retrievalRequest?.Cancel();
}
}
}

View File

@ -5,18 +5,18 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Online.API.Requests;
using osu.Game.Users;
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Online.API.Requests.Responses;
using System.Collections.Generic;
using osu.Game.Online.API;
namespace osu.Game.Overlays.Profile.Sections.Ranks
{
public class PaginatedScoreContainer : PaginatedContainer
public class PaginatedScoreContainer : PaginatedContainer<APILegacyScoreInfo>
{
private readonly bool includeWeight;
private readonly ScoreType type;
private GetUserScoresRequest request;
public PaginatedScoreContainer(ScoreType type, Bindable<User> user, string header, string missing, bool includeWeight = false)
: base(user, header, missing)
@ -29,52 +29,27 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
ItemsContainer.Direction = FillDirection.Vertical;
}
protected override void ShowMore()
protected override void UpdateItems(List<APILegacyScoreInfo> items)
{
request = new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
request.Success += scores => Schedule(() =>
{
foreach (var s in scores)
s.Ruleset = Rulesets.GetRuleset(s.RulesetID);
foreach (var item in items)
item.Ruleset = Rulesets.GetRuleset(item.RulesetID);
if (!scores.Any() && VisiblePages == 1)
{
MoreButton.Hide();
MoreButton.IsLoading = false;
MissingText.Show();
return;
}
IEnumerable<DrawableProfileScore> drawableScores;
switch (type)
{
default:
drawableScores = scores.Select(score => new DrawablePerformanceScore(score, includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null));
break;
case ScoreType.Recent:
drawableScores = scores.Select(score => new DrawableTotalScore(score));
break;
}
LoadComponentsAsync(drawableScores, s =>
{
MissingText.Hide();
MoreButton.FadeTo(scores.Count == ItemsPerPage ? 1 : 0);
MoreButton.IsLoading = false;
ItemsContainer.AddRange(s);
});
});
Api.Queue(request);
base.UpdateItems(items);
}
protected override void Dispose(bool isDisposing)
protected override APIRequest<List<APILegacyScoreInfo>> CreateRequest() =>
new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
protected override Drawable CreateDrawableItem(APILegacyScoreInfo model)
{
base.Dispose(isDisposing);
request?.Cancel();
switch (type)
{
default:
return new DrawablePerformanceScore(model, includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null);
case ScoreType.Recent:
return new DrawableTotalScore(model);
}
}
}
}

View File

@ -4,51 +4,24 @@
using osu.Framework.Graphics;
using osu.Game.Online.API.Requests;
using osu.Game.Users;
using System.Linq;
using osu.Framework.Bindables;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.API;
using System.Collections.Generic;
namespace osu.Game.Overlays.Profile.Sections.Recent
{
public class PaginatedRecentActivityContainer : PaginatedContainer
public class PaginatedRecentActivityContainer : PaginatedContainer<APIRecentActivity>
{
private GetUserRecentActivitiesRequest request;
public PaginatedRecentActivityContainer(Bindable<User> user, string header, string missing)
: base(user, header, missing)
{
ItemsPerPage = 5;
}
protected override void ShowMore()
{
request = new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++, ItemsPerPage);
request.Success += activities => Schedule(() =>
{
MoreButton.FadeTo(activities.Count == ItemsPerPage ? 1 : 0);
MoreButton.IsLoading = false;
protected override APIRequest<List<APIRecentActivity>> CreateRequest() =>
new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++, ItemsPerPage);
if (!activities.Any() && VisiblePages == 1)
{
MissingText.Show();
return;
}
MissingText.Hide();
foreach (APIRecentActivity activity in activities)
{
ItemsContainer.Add(new DrawableRecentActivity(activity));
}
});
Api.Queue(request);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
request?.Cancel();
}
protected override Drawable CreateDrawableItem(APIRecentActivity model) => new DrawableRecentActivity(model);
}
}

View File

@ -9,7 +9,7 @@ using osu.Game.Input.Bindings;
namespace osu.Game.Overlays.Volume
{
public class VolumeControlReceptor : Container, IScrollBindingHandler<GlobalAction>, IHandleGlobalInput
public class VolumeControlReceptor : Container, IScrollBindingHandler<GlobalAction>, IHandleGlobalKeyboardInput
{
public Func<GlobalAction, bool> ActionRequested;
public Func<GlobalAction, float, bool, bool> ScrollActionRequested;

View File

@ -132,6 +132,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
/// </summary>
public event Action<DrawableHitObject, ArmedState> ApplyCustomUpdateState;
#pragma warning disable 618 // (legacy state management) - can be removed 20200227
/// <summary>
/// Enables automatic transform management of this hitobject. Implementation of transforms should be done in <see cref="UpdateInitialTransforms"/> and <see cref="UpdateStateTransforms"/> only. Rewinding and removing previous states is done automatically.
/// </summary>
@ -139,6 +141,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
/// Going forward, this is the preferred way of implementing <see cref="DrawableHitObject"/>s. Previous functionality
/// is offered as a compatibility layer until all rulesets have been migrated across.
/// </remarks>
[Obsolete("Use UpdateInitialTransforms()/UpdateStateTransforms() instead")] // can be removed 20200227
protected virtual bool UseTransformStateManagement => true;
protected override void ClearInternal(bool disposeChildren = true) => throw new InvalidOperationException($"Should never clear a {nameof(DrawableHitObject)}");
@ -219,10 +222,13 @@ namespace osu.Game.Rulesets.Objects.Drawables
/// Should generally not be used when <see cref="UseTransformStateManagement"/> is true; use <see cref="UpdateStateTransforms"/> instead.
/// </summary>
/// <param name="state">The new armed state.</param>
[Obsolete("Use UpdateInitialTransforms()/UpdateStateTransforms() instead")] // can be removed 20200227
protected virtual void UpdateState(ArmedState state)
{
}
#pragma warning restore 618
#endregion
protected override void SkinChanged(ISkinSource skin, bool allowFallback)

View File

@ -220,14 +220,23 @@ namespace osu.Game.Screens.Select.Carousel
public class FilterableGroupedDifficultyIcon : GroupedDifficultyIcon
{
private readonly List<CarouselBeatmap> items;
public FilterableGroupedDifficultyIcon(List<CarouselBeatmap> items, RulesetInfo ruleset)
: base(items.Select(i => i.Beatmap).ToList(), ruleset, Color4.White)
{
items.ForEach(item => item.Filtered.ValueChanged += _ =>
{
// for now, fade the whole group based on the ratio of hidden items.
this.FadeTo(1 - 0.9f * ((float)items.Count(i => i.Filtered.Value) / items.Count), 100);
});
this.items = items;
foreach (var item in items)
item.Filtered.BindValueChanged(_ => Scheduler.AddOnce(updateFilteredDisplay));
updateFilteredDisplay();
}
private void updateFilteredDisplay()
{
// for now, fade the whole group based on the ratio of hidden items.
this.FadeTo(1 - 0.9f * ((float)items.Count(i => i.Filtered.Value) / items.Count), 100);
}
}
}

View File

@ -29,40 +29,14 @@ namespace osu.Game.Screens.Select
private readonly TabControl<GroupMode> groupTabs;
private SortMode sort = SortMode.Title;
private Bindable<SortMode> sortMode;
public SortMode Sort
{
get => sort;
set
{
if (sort != value)
{
sort = value;
FilterChanged?.Invoke(CreateCriteria());
}
}
}
private GroupMode group = GroupMode.All;
public GroupMode Group
{
get => group;
set
{
if (group != value)
{
group = value;
FilterChanged?.Invoke(CreateCriteria());
}
}
}
private Bindable<GroupMode> groupMode;
public FilterCriteria CreateCriteria() => new FilterCriteria
{
Group = group,
Sort = sort,
Group = groupMode.Value,
Sort = sortMode.Value,
SearchText = searchTextBox.Text,
AllowConvertedBeatmaps = showConverted.Value,
Ruleset = ruleset.Value
@ -122,7 +96,6 @@ namespace osu.Game.Screens.Select
Height = 24,
Width = 0.5f,
AutoSort = true,
Current = { Value = GroupMode.Title }
},
//spriteText = new OsuSpriteText
//{
@ -141,7 +114,6 @@ namespace osu.Game.Screens.Select
Width = 0.5f,
Height = 24,
AutoSort = true,
Current = { Value = SortMode.Title }
}
}
},
@ -153,8 +125,6 @@ namespace osu.Game.Screens.Select
groupTabs.PinItem(GroupMode.All);
groupTabs.PinItem(GroupMode.RecentlyPlayed);
groupTabs.Current.ValueChanged += group => Group = group.NewValue;
sortTabs.Current.ValueChanged += sort => Sort = sort.NewValue;
}
public void Deactivate()
@ -184,7 +154,18 @@ namespace osu.Game.Screens.Select
showConverted.ValueChanged += _ => updateCriteria();
ruleset.BindTo(parentRuleset);
ruleset.BindValueChanged(_ => updateCriteria(), true);
ruleset.BindValueChanged(_ => updateCriteria());
sortMode = config.GetBindable<SortMode>(OsuSetting.SongSelectSortingMode);
groupMode = config.GetBindable<GroupMode>(OsuSetting.SongSelectGroupingMode);
sortTabs.Current.BindTo(sortMode);
groupTabs.Current.BindTo(groupMode);
groupMode.BindValueChanged(_ => updateCriteria());
sortMode.BindValueChanged(_ => updateCriteria());
updateCriteria();
}
private void updateCriteria() => FilterChanged?.Invoke(CreateCriteria());

View File

@ -4,6 +4,7 @@
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using osu.Game.Audio;
namespace osu.Game.Skinning
{
@ -19,6 +20,6 @@ namespace osu.Game.Skinning
public override Texture GetTexture(string componentName) => null;
public override SampleChannel GetSample(string sampleName) => null;
public override SampleChannel GetSample(ISampleInfo sampleInfo) => null;
}
}

View File

@ -5,6 +5,7 @@ using System;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using osu.Game.Audio;
namespace osu.Game.Skinning
{
@ -17,7 +18,7 @@ namespace osu.Game.Skinning
Texture GetTexture(string componentName);
SampleChannel GetSample(string sampleName);
SampleChannel GetSample(ISampleInfo sampleInfo);
TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration;
}

View File

@ -17,6 +17,7 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores;
using osu.Framework.Text;
using osu.Game.Audio;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
@ -155,16 +156,55 @@ namespace osu.Game.Skinning
// Spacing value was reverse-engineered from the ratio of the rendered sprite size in the visual inspector vs the actual texture size
Spacing = new Vector2(-Configuration.HitCircleOverlap * 0.89f, 0)
};
default:
string lastPiece = componentName.Split('/').Last();
componentName = componentName.StartsWith("Gameplay/taiko/") ? "taiko-" + lastPiece : lastPiece;
break;
}
return getAnimation(componentName, animatable, looping);
}
public override Texture GetTexture(string componentName)
{
componentName = getFallbackName(componentName);
float ratio = 2;
var texture = Textures.Get($"{componentName}@2x");
if (texture == null)
{
ratio = 1;
texture = Textures.Get(componentName);
}
if (texture != null)
texture.ScaleAdjust = ratio;
return texture;
}
public override SampleChannel GetSample(ISampleInfo sampleInfo)
{
foreach (var lookup in sampleInfo.LookupNames)
{
var sample = Samples.Get(getFallbackName(lookup));
if (sample != null)
return sample;
}
if (sampleInfo is HitSampleInfo hsi)
// Try fallback to non-bank samples.
return Samples.Get(hsi.Name);
return null;
}
private bool hasFont(string fontName) => GetTexture($"{fontName}-0") != null;
private string getFallbackName(string componentName)
{
string lastPiece = componentName.Split('/').Last();
return componentName.StartsWith("Gameplay/taiko/") ? "taiko-" + lastPiece : lastPiece;
}
private Drawable getAnimation(string componentName, bool animatable, bool looping, string animationSeparator = "-")
{
Texture texture;
@ -200,27 +240,6 @@ namespace osu.Game.Skinning
return null;
}
public override Texture GetTexture(string componentName)
{
float ratio = 2;
var texture = Textures.Get($"{componentName}@2x");
if (texture == null)
{
ratio = 1;
texture = Textures.Get(componentName);
}
if (texture != null)
texture.ScaleAdjust = ratio;
return texture;
}
public override SampleChannel GetSample(string sampleName) => Samples.Get(sampleName);
private bool hasFont(string fontName) => GetTexture($"{fontName}-0") != null;
protected class LegacySkinResourceStore<T> : IResourceStore<byte[]>
where T : INamedFileInfo
{

View File

@ -8,6 +8,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;
using osu.Game.Audio;
using osu.Game.Configuration;
namespace osu.Game.Skinning
@ -49,13 +50,13 @@ namespace osu.Game.Skinning
return fallbackSource.GetTexture(componentName);
}
public SampleChannel GetSample(string sampleName)
public SampleChannel GetSample(ISampleInfo sampleInfo)
{
SampleChannel sourceChannel;
if (beatmapHitsounds.Value && (sourceChannel = skin?.GetSample(sampleName)) != null)
if (beatmapHitsounds.Value && (sourceChannel = skin?.GetSample(sampleInfo)) != null)
return sourceChannel;
return fallbackSource?.GetSample(sampleName);
return fallbackSource?.GetSample(sampleInfo);
}
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration

View File

@ -5,6 +5,7 @@ using System;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using osu.Game.Audio;
namespace osu.Game.Skinning
{
@ -16,7 +17,7 @@ namespace osu.Game.Skinning
public abstract Drawable GetDrawableComponent(string componentName);
public abstract SampleChannel GetSample(string sampleName);
public abstract SampleChannel GetSample(ISampleInfo sampleInfo);
public abstract Texture GetTexture(string componentName);

View File

@ -15,6 +15,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using osu.Framework.Platform;
using osu.Game.Audio;
using osu.Game.Database;
using osu.Game.IO.Archives;
@ -120,7 +121,7 @@ namespace osu.Game.Skinning
public Texture GetTexture(string componentName) => CurrentSkin.Value.GetTexture(componentName);
public SampleChannel GetSample(string sampleName) => CurrentSkin.Value.GetSample(sampleName);
public SampleChannel GetSample(ISampleInfo sampleInfo) => CurrentSkin.Value.GetSample(sampleInfo);
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration => CurrentSkin.Value.GetValue(query);
}

View File

@ -1,7 +1,6 @@
// 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.
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
@ -37,34 +36,26 @@ namespace osu.Game.Skinning
public void Play() => channels?.ForEach(c => c.Play());
public override bool IsPresent => false; // We don't need to receive updates.
public override bool IsPresent => Scheduler.HasPendingTasks;
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
{
channels = hitSamples.Select(s =>
{
var ch = loadChannel(s, skin.GetSample);
var ch = skin.GetSample(s);
if (ch == null && allowFallback)
ch = loadChannel(s, audio.Samples.Get);
foreach (var lookup in s.LookupNames)
if ((ch = audio.Samples.Get($"Gameplay/{lookup}")) != null)
break;
if (ch != null)
ch.Volume.Value = s.Volume / 100.0;
return ch;
}).Where(c => c != null).ToArray();
}
private SampleChannel loadChannel(ISampleInfo info, Func<string, SampleChannel> getSampleFunction)
{
foreach (var lookup in info.LookupNames)
{
var ch = getSampleFunction($"Gameplay/{lookup}");
if (ch == null)
continue;
ch.Volume.Value = info.Volume / 100.0;
return ch;
}
return null;
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);

View File

@ -1,7 +1,6 @@
// 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.
using System.IO;
using osu.Framework.Allocation;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
@ -17,25 +16,24 @@ namespace osu.Game.Storyboards.Drawables
/// </summary>
private const double allowable_late_start = 100;
private readonly StoryboardSample sample;
private readonly StoryboardSampleInfo sampleInfo;
private SampleChannel channel;
public override bool RemoveWhenNotAlive => false;
public DrawableStoryboardSample(StoryboardSample sample)
public DrawableStoryboardSample(StoryboardSampleInfo sampleInfo)
{
this.sample = sample;
LifetimeStart = sample.StartTime;
this.sampleInfo = sampleInfo;
LifetimeStart = sampleInfo.StartTime;
}
[BackgroundDependencyLoader]
private void load(IBindable<WorkingBeatmap> beatmap)
{
// Try first with the full name, then attempt with no path
channel = beatmap.Value.Skin.GetSample(sample.Path) ?? beatmap.Value.Skin.GetSample(Path.ChangeExtension(sample.Path, null));
channel = beatmap.Value.Skin.GetSample(sampleInfo);
if (channel != null)
channel.Volume.Value = sample.Volume / 100;
channel.Volume.Value = sampleInfo.Volume / 100.0;
}
protected override void Update()
@ -43,27 +41,27 @@ namespace osu.Game.Storyboards.Drawables
base.Update();
// TODO: this logic will need to be consolidated with other game samples like hit sounds.
if (Time.Current < sample.StartTime)
if (Time.Current < sampleInfo.StartTime)
{
// We've rewound before the start time of the sample
channel?.Stop();
// 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)
LifetimeStart = sample.StartTime;
LifetimeStart = sampleInfo.StartTime;
LifetimeEnd = double.MaxValue;
}
else if (Time.Current - Time.Elapsed < sample.StartTime)
else if (Time.Current - Time.Elapsed < sampleInfo.StartTime)
{
// 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
if (Time.Current - sample.StartTime < allowable_late_start)
if (Time.Current - sampleInfo.StartTime < allowable_late_start)
channel?.Play();
// 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)
LifetimeStart = double.MinValue;
LifetimeEnd = sample.StartTime;
LifetimeEnd = sampleInfo.StartTime;
}
}
}

View File

@ -1,21 +1,30 @@
// 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.
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Game.Audio;
using osu.Game.Storyboards.Drawables;
namespace osu.Game.Storyboards
{
public class StoryboardSample : IStoryboardElement
public class StoryboardSampleInfo : IStoryboardElement, ISampleInfo
{
public string Path { get; set; }
public string Path { get; }
public bool IsDrawable => true;
public double StartTime { get; }
public float Volume;
public int Volume { get; }
public StoryboardSample(string path, double time, float volume)
public IEnumerable<string> LookupNames => new[]
{
// Try first with the full name, then attempt with no path
Path,
System.IO.Path.ChangeExtension(Path, null),
};
public StoryboardSampleInfo(string path, double time, int volume)
{
Path = path;
StartTime = time;

View File

@ -15,7 +15,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.823.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.823.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.828.0" />
<PackageReference Include="SharpCompress" Version="0.24.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" />

View File

@ -118,8 +118,8 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.823.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.823.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.823.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.828.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.828.0" />
<PackageReference Include="SharpCompress" Version="0.24.0" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" />