mirror of
https://github.com/ppy/osu.git
synced 2025-01-15 06:42:56 +08:00
Merge branch 'master' into fix-hidden-mod-crash
This commit is contained in:
commit
5db15a6b26
@ -52,6 +52,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1202.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.1201.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.1203.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -1,6 +1,8 @@
|
||||
// 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.
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Utils;
|
||||
@ -8,6 +10,7 @@ using osu.Game.Audio;
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Utils;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects
|
||||
@ -53,19 +56,22 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
|
||||
private class BananaHitSampleInfo : HitSampleInfo, IEquatable<BananaHitSampleInfo>
|
||||
{
|
||||
private static readonly string[] lookup_names = { "metronomelow", "catch-banana" };
|
||||
private static readonly string[] lookup_names = { "Gameplay/metronomelow", "Gameplay/catch-banana" };
|
||||
|
||||
public override IEnumerable<string> LookupNames => lookup_names;
|
||||
|
||||
public BananaHitSampleInfo()
|
||||
: base(string.Empty)
|
||||
public BananaHitSampleInfo(int volume = 0)
|
||||
: base(string.Empty, volume: volume)
|
||||
{
|
||||
}
|
||||
|
||||
public bool Equals(BananaHitSampleInfo other)
|
||||
public sealed override HitSampleInfo With(Optional<string> newName = default, Optional<string?> newBank = default, Optional<string?> newSuffix = default, Optional<int> newVolume = default)
|
||||
=> new BananaHitSampleInfo(newVolume.GetOr(Volume));
|
||||
|
||||
public bool Equals(BananaHitSampleInfo? other)
|
||||
=> other != null;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
=> obj is BananaHitSampleInfo other && Equals(other);
|
||||
|
||||
public override int GetHashCode() => lookup_names.GetHashCode();
|
||||
|
@ -11,6 +11,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Skinning;
|
||||
using osu.Game.Rulesets.Osu.UI;
|
||||
@ -40,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
private Container<DrawableSliderTail> tailContainer;
|
||||
private Container<DrawableSliderTick> tickContainer;
|
||||
private Container<DrawableSliderRepeat> repeatContainer;
|
||||
private Container<PausableSkinnableSound> samplesContainer;
|
||||
private PausableSkinnableSound slidingSample;
|
||||
|
||||
public DrawableSlider()
|
||||
: this(null)
|
||||
@ -69,7 +70,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
Alpha = 0
|
||||
},
|
||||
headContainer = new Container<DrawableSliderHead> { RelativeSizeAxes = Axes.Both },
|
||||
samplesContainer = new Container<PausableSkinnableSound> { RelativeSizeAxes = Axes.Both }
|
||||
slidingSample = new PausableSkinnableSound { Looping = true }
|
||||
};
|
||||
|
||||
PositionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
|
||||
@ -100,27 +101,21 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
base.OnFree();
|
||||
|
||||
PathVersion.UnbindFrom(HitObject.Path.Version);
|
||||
}
|
||||
|
||||
private PausableSkinnableSound slidingSample;
|
||||
slidingSample.Samples = null;
|
||||
}
|
||||
|
||||
protected override void LoadSamples()
|
||||
{
|
||||
base.LoadSamples();
|
||||
|
||||
samplesContainer.Clear();
|
||||
slidingSample = null;
|
||||
|
||||
var firstSample = HitObject.Samples.FirstOrDefault();
|
||||
|
||||
if (firstSample != null)
|
||||
{
|
||||
var clone = HitObject.SampleControlPoint.ApplyTo(firstSample).With("sliderslide");
|
||||
|
||||
samplesContainer.Add(slidingSample = new PausableSkinnableSound(clone)
|
||||
{
|
||||
Looping = true
|
||||
});
|
||||
slidingSample.Samples = new ISampleInfo[] { clone };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ using osu.Framework.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
@ -33,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
private Container<DrawableSpinnerTick> ticks;
|
||||
private SpinnerBonusDisplay bonusDisplay;
|
||||
private Container<PausableSkinnableSound> samplesContainer;
|
||||
private PausableSkinnableSound spinningSample;
|
||||
|
||||
private Bindable<bool> isSpinning;
|
||||
private bool spinnerFrequencyModulate;
|
||||
@ -81,7 +82,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
Origin = Anchor.Centre,
|
||||
Y = -120,
|
||||
},
|
||||
samplesContainer = new Container<PausableSkinnableSound> { RelativeSizeAxes = Axes.Both }
|
||||
spinningSample = new PausableSkinnableSound
|
||||
{
|
||||
Volume = { Value = 0 },
|
||||
Looping = true,
|
||||
Frequency = { Value = spinning_sample_initial_frequency }
|
||||
}
|
||||
};
|
||||
|
||||
PositionBindable.BindValueChanged(pos => Position = pos.NewValue);
|
||||
@ -95,29 +101,28 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
isSpinning.BindValueChanged(updateSpinningSample);
|
||||
}
|
||||
|
||||
private PausableSkinnableSound spinningSample;
|
||||
private const float spinning_sample_initial_frequency = 1.0f;
|
||||
private const float spinning_sample_modulated_base_frequency = 0.5f;
|
||||
|
||||
protected override void OnFree()
|
||||
{
|
||||
base.OnFree();
|
||||
|
||||
spinningSample.Samples = null;
|
||||
}
|
||||
|
||||
protected override void LoadSamples()
|
||||
{
|
||||
base.LoadSamples();
|
||||
|
||||
samplesContainer.Clear();
|
||||
spinningSample = null;
|
||||
|
||||
var firstSample = HitObject.Samples.FirstOrDefault();
|
||||
|
||||
if (firstSample != null)
|
||||
{
|
||||
var clone = HitObject.SampleControlPoint.ApplyTo(firstSample).With("spinnerspin");
|
||||
|
||||
samplesContainer.Add(spinningSample = new PausableSkinnableSound(clone)
|
||||
{
|
||||
Volume = { Value = 0 },
|
||||
Looping = true,
|
||||
Frequency = { Value = spinning_sample_initial_frequency }
|
||||
});
|
||||
spinningSample.Samples = new ISampleInfo[] { clone };
|
||||
spinningSample.Frequency.Value = spinning_sample_initial_frequency;
|
||||
}
|
||||
}
|
||||
|
||||
|
78
osu.Game.Tests/Audio/SampleInfoEqualityTest.cs
Normal file
78
osu.Game.Tests/Audio/SampleInfoEqualityTest.cs
Normal file
@ -0,0 +1,78 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Game.Audio;
|
||||
|
||||
namespace osu.Game.Tests.Audio
|
||||
{
|
||||
[TestFixture]
|
||||
public class SampleInfoEqualityTest
|
||||
{
|
||||
[Test]
|
||||
public void TestSameSingleSamplesAreEqual()
|
||||
{
|
||||
var first = new SampleInfo("sample");
|
||||
var second = new SampleInfo("sample");
|
||||
|
||||
assertEquality(first, second);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDifferentSingleSamplesAreNotEqual()
|
||||
{
|
||||
var first = new SampleInfo("first");
|
||||
var second = new SampleInfo("second");
|
||||
|
||||
assertNonEquality(first, second);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDifferentCountSampleSetsAreNotEqual()
|
||||
{
|
||||
var first = new SampleInfo("sample", "extra");
|
||||
var second = new SampleInfo("sample");
|
||||
|
||||
assertNonEquality(first, second);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDifferentSampleSetsOfSameCountAreNotEqual()
|
||||
{
|
||||
var first = new SampleInfo("first", "common");
|
||||
var second = new SampleInfo("common", "second");
|
||||
|
||||
assertNonEquality(first, second);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSameOrderSameSampleSetsAreEqual()
|
||||
{
|
||||
var first = new SampleInfo("first", "second");
|
||||
var second = new SampleInfo("first", "second");
|
||||
|
||||
assertEquality(first, second);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDifferentOrderSameSampleSetsAreEqual()
|
||||
{
|
||||
var first = new SampleInfo("first", "second");
|
||||
var second = new SampleInfo("second", "first");
|
||||
|
||||
assertEquality(first, second);
|
||||
}
|
||||
|
||||
private void assertEquality(SampleInfo first, SampleInfo second)
|
||||
{
|
||||
Assert.That(first.Equals(second), Is.True);
|
||||
Assert.That(first.GetHashCode(), Is.EqualTo(second.GetHashCode()));
|
||||
}
|
||||
|
||||
private void assertNonEquality(SampleInfo first, SampleInfo second)
|
||||
{
|
||||
Assert.That(first.Equals(second), Is.False);
|
||||
Assert.That(first.GetHashCode(), Is.Not.EqualTo(second.GetHashCode()));
|
||||
}
|
||||
}
|
||||
}
|
@ -4,10 +4,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Drawing;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Tournament.Screens.Ladder.Components;
|
||||
using SixLabors.Primitives;
|
||||
|
||||
namespace osu.Game.Tournament.Models
|
||||
{
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
@ -16,7 +17,6 @@ using osu.Game.Tournament.Screens.Ladder;
|
||||
using osu.Game.Tournament.Screens.Ladder.Components;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using SixLabors.Primitives;
|
||||
|
||||
namespace osu.Game.Tournament.Screens.Editors
|
||||
{
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
@ -13,7 +14,6 @@ using osu.Game.Tournament.Models;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osuTK.Input;
|
||||
using SixLabors.Primitives;
|
||||
|
||||
namespace osu.Game.Tournament.Screens.Ladder.Components
|
||||
{
|
||||
|
@ -1,24 +1,41 @@
|
||||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Audio
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a gameplay sample.
|
||||
/// </summary>
|
||||
public class SampleInfo : ISampleInfo
|
||||
public class SampleInfo : ISampleInfo, IEquatable<SampleInfo>
|
||||
{
|
||||
private readonly string[] sampleNames;
|
||||
|
||||
public SampleInfo(params string[] sampleNames)
|
||||
{
|
||||
this.sampleNames = sampleNames;
|
||||
Array.Sort(sampleNames);
|
||||
}
|
||||
|
||||
public IEnumerable<string> LookupNames => sampleNames;
|
||||
|
||||
public int Volume { get; } = 100;
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(
|
||||
StructuralComparisons.StructuralEqualityComparer.GetHashCode(sampleNames),
|
||||
Volume);
|
||||
}
|
||||
|
||||
public bool Equals(SampleInfo other)
|
||||
=> other != null && sampleNames.SequenceEqual(other.sampleNames);
|
||||
|
||||
public override bool Equals(object obj)
|
||||
=> obj is SampleInfo other && Equals(other);
|
||||
}
|
||||
}
|
||||
|
@ -116,13 +116,13 @@ namespace osu.Game.Graphics
|
||||
switch (screenshotFormat.Value)
|
||||
{
|
||||
case ScreenshotFormat.Png:
|
||||
image.SaveAsPng(stream);
|
||||
await image.SaveAsPngAsync(stream);
|
||||
break;
|
||||
|
||||
case ScreenshotFormat.Jpg:
|
||||
const int jpeg_quality = 92;
|
||||
|
||||
image.SaveAsJpeg(stream, new JpegEncoder { Quality = jpeg_quality });
|
||||
await image.SaveAsJpegAsync(stream, new JpegEncoder { Quality = jpeg_quality });
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -75,6 +75,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
StarDifficulty = starDifficulty,
|
||||
OnlineBeatmapID = OnlineBeatmapID,
|
||||
Version = version,
|
||||
// this is actually an incorrect mapping (Length is calculated as drain length in lazer's import process, see BeatmapManager.calculateLength).
|
||||
Length = TimeSpan.FromSeconds(length).TotalMilliseconds,
|
||||
Status = Status,
|
||||
BeatmapSet = set,
|
||||
|
16
osu.Game/Online/Multiplayer/PlaylistExtensions.cs
Normal file
16
osu.Game/Online/Multiplayer/PlaylistExtensions.cs
Normal file
@ -0,0 +1,16 @@
|
||||
// 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 Humanizer;
|
||||
using Humanizer.Localisation;
|
||||
using osu.Framework.Bindables;
|
||||
|
||||
namespace osu.Game.Online.Multiplayer
|
||||
{
|
||||
public static class PlaylistExtensions
|
||||
{
|
||||
public static string GetTotalDuration(this BindableList<PlaylistItem> playlist) =>
|
||||
playlist.Select(p => p.Beatmap.Value.Length).Sum().Milliseconds().Humanize(minUnit: TimeUnit.Second, maxUnit: TimeUnit.Hour, precision: 2);
|
||||
}
|
||||
}
|
@ -10,7 +10,6 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.TypeExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Threading;
|
||||
@ -156,8 +155,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IPooledHitObjectProvider pooledObjectProvider { get; set; }
|
||||
|
||||
private Container<PausableSkinnableSound> samplesContainer;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the initialization logic in <see cref="Playfield" /> has applied.
|
||||
/// </summary>
|
||||
@ -181,7 +178,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
config.BindWith(OsuSetting.PositionalHitSounds, userPositionalHitSounds);
|
||||
|
||||
// Explicit non-virtual function call.
|
||||
base.AddInternal(samplesContainer = new Container<PausableSkinnableSound> { RelativeSizeAxes = Axes.Both });
|
||||
base.AddInternal(Samples = new PausableSkinnableSound());
|
||||
}
|
||||
|
||||
protected override void LoadAsyncComplete()
|
||||
@ -305,6 +302,9 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
// In order to stop this needless update, the event is unbound and re-bound as late as possible in Apply().
|
||||
samplesBindable.CollectionChanged -= onSamplesChanged;
|
||||
|
||||
// Release the samples for other hitobjects to use.
|
||||
Samples.Samples = null;
|
||||
|
||||
if (nestedHitObjects.IsValueCreated)
|
||||
{
|
||||
foreach (var obj in nestedHitObjects.Value)
|
||||
@ -362,9 +362,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
/// </summary>
|
||||
protected virtual void LoadSamples()
|
||||
{
|
||||
samplesContainer.Clear();
|
||||
Samples = null;
|
||||
|
||||
var samples = GetSamples().ToArray();
|
||||
|
||||
if (samples.Length <= 0)
|
||||
@ -376,7 +373,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
+ $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}.");
|
||||
}
|
||||
|
||||
samplesContainer.Add(Samples = new PausableSkinnableSound(samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s))));
|
||||
Samples.Samples = samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)).Cast<ISampleInfo>().ToArray();
|
||||
}
|
||||
|
||||
private void onSamplesChanged(object sender, NotifyCollectionChangedEventArgs e) => LoadSamples();
|
||||
|
@ -8,20 +8,24 @@ using JetBrains.Annotations;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Pooling;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
[Cached(typeof(IPooledHitObjectProvider))]
|
||||
public abstract class Playfield : CompositeDrawable, IPooledHitObjectProvider
|
||||
[Cached(typeof(IPooledSampleProvider))]
|
||||
public abstract class Playfield : CompositeDrawable, IPooledHitObjectProvider, IPooledSampleProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Invoked when a <see cref="DrawableHitObject"/> is judged.
|
||||
@ -81,6 +85,12 @@ namespace osu.Game.Rulesets.UI
|
||||
/// </summary>
|
||||
public readonly BindableBool DisplayJudgements = new BindableBool(true);
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IReadOnlyList<Mod> mods { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private ISampleStore sampleStore { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="Playfield"/>.
|
||||
/// </summary>
|
||||
@ -97,9 +107,6 @@ namespace osu.Game.Rulesets.UI
|
||||
}));
|
||||
}
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IReadOnlyList<Mod> mods { get; set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
@ -364,6 +371,29 @@ namespace osu.Game.Rulesets.UI
|
||||
});
|
||||
}
|
||||
|
||||
private readonly Dictionary<ISampleInfo, DrawablePool<PoolableSkinnableSample>> samplePools = new Dictionary<ISampleInfo, DrawablePool<PoolableSkinnableSample>>();
|
||||
|
||||
public PoolableSkinnableSample GetPooledSample(ISampleInfo sampleInfo)
|
||||
{
|
||||
if (!samplePools.TryGetValue(sampleInfo, out var existingPool))
|
||||
AddInternal(samplePools[sampleInfo] = existingPool = new DrawableSamplePool(sampleInfo, 1));
|
||||
|
||||
return existingPool.Get();
|
||||
}
|
||||
|
||||
private class DrawableSamplePool : DrawablePool<PoolableSkinnableSample>
|
||||
{
|
||||
private readonly ISampleInfo sampleInfo;
|
||||
|
||||
public DrawableSamplePool(ISampleInfo sampleInfo, int initialSize, int? maximumSize = null)
|
||||
: base(initialSize, maximumSize)
|
||||
{
|
||||
this.sampleInfo = sampleInfo;
|
||||
}
|
||||
|
||||
protected override PoolableSkinnableSample CreateNewDrawable() => base.CreateNewDrawable().With(d => d.Apply(sampleInfo));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Editor logic
|
||||
|
22
osu.Game/Screens/Multi/Components/OverlinedPlaylistHeader.cs
Normal file
22
osu.Game/Screens/Multi/Components/OverlinedPlaylistHeader.cs
Normal file
@ -0,0 +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 osu.Game.Online.Multiplayer;
|
||||
|
||||
namespace osu.Game.Screens.Multi.Components
|
||||
{
|
||||
public class OverlinedPlaylistHeader : OverlinedHeader
|
||||
{
|
||||
public OverlinedPlaylistHeader()
|
||||
: base("Playlist")
|
||||
{
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
Playlist.BindCollectionChanged((_, __) => Details.Value = Playlist.GetTotalDuration(), true);
|
||||
}
|
||||
}
|
||||
}
|
@ -67,7 +67,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components
|
||||
}
|
||||
}
|
||||
},
|
||||
new Drawable[] { new OverlinedHeader("Playlist"), },
|
||||
new Drawable[] { new OverlinedPlaylistHeader(), },
|
||||
new Drawable[]
|
||||
{
|
||||
new DrawableRoomPlaylist(false, false)
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using Humanizer;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
@ -69,6 +70,7 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
private OsuSpriteText typeLabel;
|
||||
private LoadingLayer loadingLayer;
|
||||
private DrawableRoomPlaylist playlist;
|
||||
private OsuSpriteText playlistLength;
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IRoomManager manager { get; set; }
|
||||
@ -229,6 +231,15 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
playlist = new DrawableRoomPlaylist(true, true) { RelativeSizeAxes = Axes.Both }
|
||||
},
|
||||
new Drawable[]
|
||||
{
|
||||
playlistLength = new OsuSpriteText
|
||||
{
|
||||
Margin = new MarginPadding { Vertical = 5 },
|
||||
Colour = colours.Yellow,
|
||||
Font = OsuFont.GetFont(size: 12),
|
||||
}
|
||||
},
|
||||
new Drawable[]
|
||||
{
|
||||
new PurpleTriangleButton
|
||||
{
|
||||
@ -243,6 +254,7 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
{
|
||||
new Dimension(),
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -315,6 +327,7 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
Duration.BindValueChanged(duration => DurationField.Current.Value = duration.NewValue, true);
|
||||
|
||||
playlist.Items.BindTo(Playlist);
|
||||
Playlist.BindCollectionChanged(onPlaylistChanged, true);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
@ -324,6 +337,9 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
ApplyButton.Enabled.Value = hasValidSettings;
|
||||
}
|
||||
|
||||
private void onPlaylistChanged(object sender, NotifyCollectionChangedEventArgs e) =>
|
||||
playlistLength.Text = $"Length: {Playlist.GetTotalDuration()}";
|
||||
|
||||
private bool hasValidSettings => RoomID.Value == null && NameField.Text.Length > 0 && Playlist.Count > 0;
|
||||
|
||||
private void apply()
|
||||
|
@ -135,7 +135,7 @@ namespace osu.Game.Screens.Multi.Match
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[] { new OverlinedHeader("Playlist"), },
|
||||
new Drawable[] { new OverlinedPlaylistHeader(), },
|
||||
new Drawable[]
|
||||
{
|
||||
new DrawableRoomPlaylistWithResults
|
||||
|
@ -914,6 +914,9 @@ namespace osu.Game.Screens.Select
|
||||
{
|
||||
// size is determined by the carousel itself, due to not all content necessarily being loaded.
|
||||
ScrollContent.AutoSizeAxes = Axes.None;
|
||||
|
||||
// the scroll container may get pushed off-screen by global screen changes, but we still want panels to display outside of the bounds.
|
||||
Masking = false;
|
||||
}
|
||||
|
||||
// ReSharper disable once OptionalParameterHierarchyMismatch 2020.3 EAP4 bug. (https://youtrack.jetbrains.com/issue/RSRP-481535?p=RIDER-51910)
|
||||
|
@ -100,8 +100,14 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
background = new DelayedLoadWrapper(() => new SetPanelBackground(manager.GetWorkingBeatmap(beatmapSet.Beatmaps.FirstOrDefault()))
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
}, 300),
|
||||
mainFlow = new DelayedLoadWrapper(() => new SetPanelContent((CarouselBeatmapSet)Item), 100),
|
||||
}, 300)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
mainFlow = new DelayedLoadWrapper(() => new SetPanelContent((CarouselBeatmapSet)Item), 100)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
};
|
||||
|
||||
background.DelayedLoadComplete += fadeContentIn;
|
||||
|
22
osu.Game/Skinning/IPooledSampleProvider.cs
Normal file
22
osu.Game/Skinning/IPooledSampleProvider.cs
Normal file
@ -0,0 +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 JetBrains.Annotations;
|
||||
using osu.Game.Audio;
|
||||
|
||||
namespace osu.Game.Skinning
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides pooled samples to be used by <see cref="SkinnableSound"/>s.
|
||||
/// </summary>
|
||||
internal interface IPooledSampleProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves a <see cref="PoolableSkinnableSample"/> from a pool.
|
||||
/// </summary>
|
||||
/// <param name="sampleInfo">The <see cref="SampleInfo"/> describing the sample to retrieve.</param>
|
||||
/// <returns>The <see cref="PoolableSkinnableSample"/>.</returns>
|
||||
[CanBeNull]
|
||||
PoolableSkinnableSample GetPooledSample(ISampleInfo sampleInfo);
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Threading;
|
||||
@ -14,13 +15,17 @@ namespace osu.Game.Skinning
|
||||
{
|
||||
protected bool RequestedPlaying { get; private set; }
|
||||
|
||||
public PausableSkinnableSound(ISampleInfo hitSamples)
|
||||
: base(hitSamples)
|
||||
public PausableSkinnableSound()
|
||||
{
|
||||
}
|
||||
|
||||
public PausableSkinnableSound(IEnumerable<ISampleInfo> hitSamples)
|
||||
: base(hitSamples)
|
||||
public PausableSkinnableSound([NotNull] IEnumerable<ISampleInfo> samples)
|
||||
: base(samples)
|
||||
{
|
||||
}
|
||||
|
||||
public PausableSkinnableSound([NotNull] ISampleInfo sample)
|
||||
: base(sample)
|
||||
{
|
||||
}
|
||||
|
||||
|
168
osu.Game/Skinning/PoolableSkinnableSample.cs
Normal file
168
osu.Game/Skinning/PoolableSkinnableSample.cs
Normal file
@ -0,0 +1,168 @@
|
||||
// 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 JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Audio;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Audio;
|
||||
|
||||
namespace osu.Game.Skinning
|
||||
{
|
||||
/// <summary>
|
||||
/// A sample corresponding to an <see cref="ISampleInfo"/> that supports being pooled and responding to skin changes.
|
||||
/// </summary>
|
||||
public class PoolableSkinnableSample : SkinReloadableDrawable, IAggregateAudioAdjustment, IAdjustableAudioComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// The currently-loaded <see cref="DrawableSample"/>.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
public DrawableSample Sample { get; private set; }
|
||||
|
||||
private readonly AudioContainer<DrawableSample> sampleContainer;
|
||||
private ISampleInfo sampleInfo;
|
||||
|
||||
[Resolved]
|
||||
private ISampleStore sampleStore { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="PoolableSkinnableSample"/> with no applied <see cref="ISampleInfo"/>.
|
||||
/// An <see cref="ISampleInfo"/> can be applied later via <see cref="Apply"/>.
|
||||
/// </summary>
|
||||
public PoolableSkinnableSample()
|
||||
{
|
||||
InternalChild = sampleContainer = new AudioContainer<DrawableSample> { RelativeSizeAxes = Axes.Both };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="PoolableSkinnableSample"/> with an applied <see cref="ISampleInfo"/>.
|
||||
/// </summary>
|
||||
/// <param name="sampleInfo">The <see cref="ISampleInfo"/> to attach.</param>
|
||||
public PoolableSkinnableSample(ISampleInfo sampleInfo)
|
||||
: this()
|
||||
{
|
||||
Apply(sampleInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies an <see cref="ISampleInfo"/> that describes the sample to retrieve.
|
||||
/// Only one <see cref="ISampleInfo"/> can ever be applied to a <see cref="PoolableSkinnableSample"/>.
|
||||
/// </summary>
|
||||
/// <param name="sampleInfo">The <see cref="ISampleInfo"/> to apply.</param>
|
||||
/// <exception cref="InvalidOperationException">If an <see cref="ISampleInfo"/> has already been applied to this <see cref="PoolableSkinnableSample"/>.</exception>
|
||||
public void Apply(ISampleInfo sampleInfo)
|
||||
{
|
||||
if (this.sampleInfo != null)
|
||||
throw new InvalidOperationException($"A {nameof(PoolableSkinnableSample)} cannot be applied multiple {nameof(ISampleInfo)}s.");
|
||||
|
||||
this.sampleInfo = sampleInfo;
|
||||
|
||||
Volume.Value = sampleInfo.Volume / 100.0;
|
||||
|
||||
if (LoadState >= LoadState.Ready)
|
||||
updateSample();
|
||||
}
|
||||
|
||||
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||
{
|
||||
base.SkinChanged(skin, allowFallback);
|
||||
updateSample();
|
||||
}
|
||||
|
||||
private void updateSample()
|
||||
{
|
||||
if (sampleInfo == null)
|
||||
return;
|
||||
|
||||
bool wasPlaying = Playing;
|
||||
|
||||
sampleContainer.Clear();
|
||||
Sample = null;
|
||||
|
||||
var ch = CurrentSkin.GetSample(sampleInfo);
|
||||
|
||||
if (ch == null && AllowDefaultFallback)
|
||||
{
|
||||
foreach (var lookup in sampleInfo.LookupNames)
|
||||
{
|
||||
if ((ch = sampleStore.Get(lookup)) != null)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ch == null)
|
||||
return;
|
||||
|
||||
sampleContainer.Add(Sample = new DrawableSample(ch) { Looping = Looping });
|
||||
|
||||
// Start playback internally for the new sample if the previous one was playing beforehand.
|
||||
if (wasPlaying)
|
||||
Play();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plays the sample.
|
||||
/// </summary>
|
||||
/// <param name="restart">Whether to play the sample from the beginning.</param>
|
||||
public void Play(bool restart = true) => Sample?.Play(restart);
|
||||
|
||||
/// <summary>
|
||||
/// Stops the sample.
|
||||
/// </summary>
|
||||
public void Stop() => Sample?.Stop();
|
||||
|
||||
/// <summary>
|
||||
/// Whether the sample is currently playing.
|
||||
/// </summary>
|
||||
public bool Playing => Sample?.Playing ?? false;
|
||||
|
||||
private bool looping;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the sample should loop on completion.
|
||||
/// </summary>
|
||||
public bool Looping
|
||||
{
|
||||
get => looping;
|
||||
set
|
||||
{
|
||||
looping = value;
|
||||
|
||||
if (Sample != null)
|
||||
Sample.Looping = value;
|
||||
}
|
||||
}
|
||||
|
||||
#region Re-expose AudioContainer
|
||||
|
||||
public BindableNumber<double> Volume => sampleContainer.Volume;
|
||||
|
||||
public BindableNumber<double> Balance => sampleContainer.Balance;
|
||||
|
||||
public BindableNumber<double> Frequency => sampleContainer.Frequency;
|
||||
|
||||
public BindableNumber<double> Tempo => sampleContainer.Tempo;
|
||||
|
||||
public void AddAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable) => sampleContainer.AddAdjustment(type, adjustBindable);
|
||||
|
||||
public void RemoveAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable) => sampleContainer.RemoveAdjustment(type, adjustBindable);
|
||||
|
||||
public void RemoveAllAdjustments(AdjustableProperty type) => sampleContainer.RemoveAllAdjustments(type);
|
||||
|
||||
public IBindable<double> AggregateVolume => sampleContainer.AggregateVolume;
|
||||
|
||||
public IBindable<double> AggregateBalance => sampleContainer.AggregateBalance;
|
||||
|
||||
public IBindable<double> AggregateFrequency => sampleContainer.AggregateFrequency;
|
||||
|
||||
public IBindable<double> AggregateTempo => sampleContainer.AggregateTempo;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -27,7 +27,7 @@ namespace osu.Game.Skinning
|
||||
/// <summary>
|
||||
/// Whether fallback to default skin should be allowed if the custom skin is missing this resource.
|
||||
/// </summary>
|
||||
private bool allowDefaultFallback => allowFallback == null || allowFallback.Invoke(CurrentSkin);
|
||||
protected bool AllowDefaultFallback => allowFallback == null || allowFallback.Invoke(CurrentSkin);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="SkinReloadableDrawable"/>
|
||||
@ -58,7 +58,7 @@ namespace osu.Game.Skinning
|
||||
|
||||
private void skinChanged()
|
||||
{
|
||||
SkinChanged(CurrentSkin, allowDefaultFallback);
|
||||
SkinChanged(CurrentSkin, AllowDefaultFallback);
|
||||
OnSkinChanged?.Invoke();
|
||||
}
|
||||
|
||||
|
@ -1,26 +1,27 @@
|
||||
// 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 JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Audio;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Audio;
|
||||
|
||||
namespace osu.Game.Skinning
|
||||
{
|
||||
/// <summary>
|
||||
/// A sound consisting of one or more samples to be played.
|
||||
/// </summary>
|
||||
public class SkinnableSound : SkinReloadableDrawable, IAdjustableAudioComponent
|
||||
{
|
||||
private readonly ISampleInfo[] hitSamples;
|
||||
|
||||
[Resolved]
|
||||
private ISampleStore samples { get; set; }
|
||||
|
||||
public override bool RemoveWhenNotAlive => false;
|
||||
public override bool RemoveCompletedTransforms => false;
|
||||
|
||||
@ -34,21 +35,74 @@ namespace osu.Game.Skinning
|
||||
/// </remarks>
|
||||
protected bool PlayWhenZeroVolume => Looping;
|
||||
|
||||
protected readonly AudioContainer<DrawableSample> SamplesContainer;
|
||||
/// <summary>
|
||||
/// All raw <see cref="DrawableSamples"/>s contained in this <see cref="SkinnableSound"/>.
|
||||
/// </summary>
|
||||
[NotNull, ItemNotNull]
|
||||
protected IEnumerable<DrawableSample> DrawableSamples => samplesContainer.Select(c => c.Sample).Where(s => s != null);
|
||||
|
||||
public SkinnableSound(ISampleInfo hitSamples)
|
||||
: this(new[] { hitSamples })
|
||||
private readonly AudioContainer<PoolableSkinnableSample> samplesContainer;
|
||||
|
||||
[Resolved]
|
||||
private ISampleStore sampleStore { get; set; }
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IPooledSampleProvider samplePool { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="SkinnableSound"/>.
|
||||
/// </summary>
|
||||
public SkinnableSound()
|
||||
{
|
||||
InternalChild = samplesContainer = new AudioContainer<PoolableSkinnableSample>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="SkinnableSound"/> with some initial samples.
|
||||
/// </summary>
|
||||
/// <param name="samples">The initial samples.</param>
|
||||
public SkinnableSound([NotNull] IEnumerable<ISampleInfo> samples)
|
||||
: this()
|
||||
{
|
||||
this.samples = samples.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="SkinnableSound"/> with an initial sample.
|
||||
/// </summary>
|
||||
/// <param name="sample">The initial sample.</param>
|
||||
public SkinnableSound([NotNull] ISampleInfo sample)
|
||||
: this(new[] { sample })
|
||||
{
|
||||
}
|
||||
|
||||
public SkinnableSound(IEnumerable<ISampleInfo> hitSamples)
|
||||
private ISampleInfo[] samples = Array.Empty<ISampleInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// The samples that should be played.
|
||||
/// </summary>
|
||||
public ISampleInfo[] Samples
|
||||
{
|
||||
this.hitSamples = hitSamples.ToArray();
|
||||
InternalChild = SamplesContainer = new AudioContainer<DrawableSample>();
|
||||
get => samples;
|
||||
set
|
||||
{
|
||||
value ??= Array.Empty<ISampleInfo>();
|
||||
|
||||
if (samples == value)
|
||||
return;
|
||||
|
||||
samples = value;
|
||||
|
||||
if (LoadState >= LoadState.Ready)
|
||||
updateSamples();
|
||||
}
|
||||
}
|
||||
|
||||
private bool looping;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the samples should loop on completion.
|
||||
/// </summary>
|
||||
public bool Looping
|
||||
{
|
||||
get => looping;
|
||||
@ -58,77 +112,80 @@ namespace osu.Game.Skinning
|
||||
|
||||
looping = value;
|
||||
|
||||
SamplesContainer.ForEach(c => c.Looping = looping);
|
||||
samplesContainer.ForEach(c => c.Looping = looping);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plays the samples.
|
||||
/// </summary>
|
||||
public virtual void Play()
|
||||
{
|
||||
SamplesContainer.ForEach(c =>
|
||||
samplesContainer.ForEach(c =>
|
||||
{
|
||||
if (PlayWhenZeroVolume || c.AggregateVolume.Value > 0)
|
||||
c.Play();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the samples.
|
||||
/// </summary>
|
||||
public virtual void Stop()
|
||||
{
|
||||
SamplesContainer.ForEach(c => c.Stop());
|
||||
samplesContainer.ForEach(c => c.Stop());
|
||||
}
|
||||
|
||||
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||
{
|
||||
base.SkinChanged(skin, allowFallback);
|
||||
updateSamples();
|
||||
}
|
||||
|
||||
private void updateSamples()
|
||||
{
|
||||
bool wasPlaying = IsPlaying;
|
||||
|
||||
var channels = hitSamples.Select(s =>
|
||||
// Remove all pooled samples (return them to the pool), and dispose the rest.
|
||||
samplesContainer.RemoveAll(s => s.IsInPool);
|
||||
samplesContainer.Clear();
|
||||
|
||||
foreach (var s in samples)
|
||||
{
|
||||
var ch = skin.GetSample(s);
|
||||
var sample = samplePool?.GetPooledSample(s) ?? new PoolableSkinnableSample(s);
|
||||
sample.Looping = Looping;
|
||||
sample.Volume.Value = s.Volume / 100.0;
|
||||
|
||||
if (ch == null && allowFallback)
|
||||
{
|
||||
foreach (var lookup in s.LookupNames)
|
||||
{
|
||||
if ((ch = samples.Get(lookup)) != null)
|
||||
break;
|
||||
}
|
||||
}
|
||||
samplesContainer.Add(sample);
|
||||
}
|
||||
|
||||
if (ch != null)
|
||||
{
|
||||
ch.Looping = looping;
|
||||
ch.Volume.Value = s.Volume / 100.0;
|
||||
}
|
||||
|
||||
return ch;
|
||||
}).Where(c => c != null);
|
||||
|
||||
SamplesContainer.ChildrenEnumerable = channels.Select(c => new DrawableSample(c));
|
||||
|
||||
// Start playback internally for the new samples if the previous ones were playing beforehand.
|
||||
if (wasPlaying)
|
||||
Play();
|
||||
}
|
||||
|
||||
#region Re-expose AudioContainer
|
||||
|
||||
public BindableNumber<double> Volume => SamplesContainer.Volume;
|
||||
public BindableNumber<double> Volume => samplesContainer.Volume;
|
||||
|
||||
public BindableNumber<double> Balance => SamplesContainer.Balance;
|
||||
public BindableNumber<double> Balance => samplesContainer.Balance;
|
||||
|
||||
public BindableNumber<double> Frequency => SamplesContainer.Frequency;
|
||||
public BindableNumber<double> Frequency => samplesContainer.Frequency;
|
||||
|
||||
public BindableNumber<double> Tempo => SamplesContainer.Tempo;
|
||||
public BindableNumber<double> Tempo => samplesContainer.Tempo;
|
||||
|
||||
public void AddAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable)
|
||||
=> SamplesContainer.AddAdjustment(type, adjustBindable);
|
||||
=> samplesContainer.AddAdjustment(type, adjustBindable);
|
||||
|
||||
public void RemoveAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable)
|
||||
=> SamplesContainer.RemoveAdjustment(type, adjustBindable);
|
||||
=> samplesContainer.RemoveAdjustment(type, adjustBindable);
|
||||
|
||||
public void RemoveAllAdjustments(AdjustableProperty type)
|
||||
=> SamplesContainer.RemoveAllAdjustments(type);
|
||||
=> samplesContainer.RemoveAllAdjustments(type);
|
||||
|
||||
public bool IsPlaying => SamplesContainer.Any(s => s.Playing);
|
||||
/// <summary>
|
||||
/// Whether any samples are currently playing.
|
||||
/// </summary>
|
||||
public bool IsPlaying => samplesContainer.Any(s => s.Playing);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ namespace osu.Game.Storyboards.Drawables
|
||||
|
||||
foreach (var mod in mods.Value.OfType<IApplicableToSample>())
|
||||
{
|
||||
foreach (var sample in SamplesContainer)
|
||||
foreach (var sample in DrawableSamples)
|
||||
mod.ApplyToSample(sample);
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ namespace osu.Game.Tests.Beatmaps
|
||||
BeatmapInfo.BeatmapSet.Metadata = BeatmapInfo.Metadata;
|
||||
BeatmapInfo.BeatmapSet.Files = new List<BeatmapSetFileInfo>();
|
||||
BeatmapInfo.BeatmapSet.Beatmaps = new List<BeatmapInfo> { BeatmapInfo };
|
||||
BeatmapInfo.Length = 75000;
|
||||
BeatmapInfo.BeatmapSet.OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
Status = BeatmapSetOnlineStatus.Ranked,
|
||||
|
@ -26,7 +26,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.1201.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.1203.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1202.0" />
|
||||
<PackageReference Include="Sentry" Version="2.1.8" />
|
||||
<PackageReference Include="SharpCompress" Version="0.26.0" />
|
||||
|
@ -70,7 +70,7 @@
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.1201.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.1203.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1202.0" />
|
||||
</ItemGroup>
|
||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
||||
@ -88,7 +88,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.1201.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.1203.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.26.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user