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

Merge branch 'master'

Conflicts:
	osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs
This commit is contained in:
Dean Herbert 2019-09-05 14:40:30 +09:00
commit c0bcbfd892
18 changed files with 293 additions and 35 deletions

View File

@ -2,7 +2,5 @@ clone_depth: 1
version: '{branch}-{build}'
image: Previous Visual Studio 2017
test: off
install:
- cmd: git submodule update --init --recursive --depth=5
build_script:
- cmd: PowerShell -Version 2.0 .\build.ps1

10
appveyor_deploy.yml Normal file
View File

@ -0,0 +1,10 @@
clone_depth: 1
version: '{build}'
image: Previous Visual Studio 2017
test: off
skip_non_tags: true
build_script:
- cmd: PowerShell -Version 2.0 .\build.ps1
deploy:
- provider: Environment
name: nuget

View File

@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Catch.Tests
{
switch (component.LookupName)
{
case "Gameplay/Catch/fruit-catcher-idle":
case "Gameplay/catch/fruit-catcher-idle":
return new CatcherCustomSkin();
}

View File

@ -143,7 +143,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
// 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);
protected override string SampleNamespace => "Taiko";
protected override string SampleNamespace => "taiko";
protected virtual TaikoPiece CreateMainPiece() => new CirclePiece();

View File

@ -132,10 +132,10 @@ namespace osu.Game.Rulesets.Taiko.UI
[BackgroundDependencyLoader]
private void load(TextureStore textures, OsuColour colours)
{
rim.Texture = textures.Get(@"Gameplay/Taiko/taiko-drum-outer");
rimHit.Texture = textures.Get(@"Gameplay/Taiko/taiko-drum-outer-hit");
centre.Texture = textures.Get(@"Gameplay/Taiko/taiko-drum-inner");
centreHit.Texture = textures.Get(@"Gameplay/Taiko/taiko-drum-inner-hit");
rim.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-outer");
rimHit.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-outer-hit");
centre.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-inner");
centreHit.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-inner-hit");
rimHit.Colour = colours.Blue;
centreHit.Colour = colours.Pink;

View File

@ -119,6 +119,53 @@ namespace osu.Game.Tests.Chat
Assert.AreEqual(11, result.Links[0].Length);
}
[Test]
public void TestOldFormatLinkWithBalancedBrackets()
{
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a (tricky (one))[https://osu.ppy.sh]!" });
Assert.AreEqual("This is a tricky (one)!", result.DisplayContent);
Assert.AreEqual(1, result.Links.Count);
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
Assert.AreEqual(10, result.Links[0].Index);
Assert.AreEqual(12, result.Links[0].Length);
}
[Test]
public void TestOldFormatLinkWithEscapedBrackets()
{
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is (another loose bracket \\))[https://osu.ppy.sh]." });
Assert.AreEqual("This is another loose bracket ).", result.DisplayContent);
Assert.AreEqual(1, result.Links.Count);
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
Assert.AreEqual(8, result.Links[0].Index);
Assert.AreEqual(23, result.Links[0].Length);
}
[Test]
public void TestOldFormatWithBackslashes()
{
Message result = MessageFormatter.FormatMessage(new Message { Content = "This link (should end with a backslash \\)[https://osu.ppy.sh]." });
Assert.AreEqual("This link should end with a backslash \\.", result.DisplayContent);
Assert.AreEqual(1, result.Links.Count);
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
Assert.AreEqual(10, result.Links[0].Index);
Assert.AreEqual(29, result.Links[0].Length);
}
[Test]
public void TestOldFormatLinkWithEscapedAndBalancedBrackets()
{
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a (\\)super\\(\\( tricky (one))[https://osu.ppy.sh]!" });
Assert.AreEqual("This is a )super(( tricky (one)!", result.DisplayContent);
Assert.AreEqual(1, result.Links.Count);
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
Assert.AreEqual(10, result.Links[0].Index);
Assert.AreEqual(21, result.Links[0].Length);
}
[Test]
public void TestNewFormatLink()
{
@ -131,6 +178,42 @@ namespace osu.Game.Tests.Chat
Assert.AreEqual(11, result.Links[0].Length);
}
[Test]
public void TestNewFormatLinkWithEscapedBrackets()
{
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [https://osu.ppy.sh nasty link with escaped brackets: \\] and \\[]" });
Assert.AreEqual("This is a nasty link with escaped brackets: ] and [", result.DisplayContent);
Assert.AreEqual(1, result.Links.Count);
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
Assert.AreEqual(10, result.Links[0].Index);
Assert.AreEqual(41, result.Links[0].Length);
}
[Test]
public void TestNewFormatLinkWithBackslashesInside()
{
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [https://osu.ppy.sh link \\ with \\ backslashes \\]" });
Assert.AreEqual("This is a link \\ with \\ backslashes \\", result.DisplayContent);
Assert.AreEqual(1, result.Links.Count);
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
Assert.AreEqual(10, result.Links[0].Index);
Assert.AreEqual(27, result.Links[0].Length);
}
[Test]
public void TestNewFormatLinkWithEscapedAndBalancedBrackets()
{
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [https://osu.ppy.sh [link [with \\] too many brackets \\[ ]]]" });
Assert.AreEqual("This is a [link [with ] too many brackets [ ]]", result.DisplayContent);
Assert.AreEqual(1, result.Links.Count);
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
Assert.AreEqual(10, result.Links[0].Index);
Assert.AreEqual(36, result.Links[0].Length);
}
[Test]
public void TestMarkdownFormatLink()
{
@ -143,6 +226,53 @@ namespace osu.Game.Tests.Chat
Assert.AreEqual(11, result.Links[0].Length);
}
[Test]
public void TestMarkdownFormatLinkWithBalancedBrackets()
{
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [tricky [one]](https://osu.ppy.sh)!" });
Assert.AreEqual("This is a tricky [one]!", result.DisplayContent);
Assert.AreEqual(1, result.Links.Count);
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
Assert.AreEqual(10, result.Links[0].Index);
Assert.AreEqual(12, result.Links[0].Length);
}
[Test]
public void TestMarkdownFormatLinkWithEscapedBrackets()
{
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is [another loose bracket \\]](https://osu.ppy.sh)." });
Assert.AreEqual("This is another loose bracket ].", result.DisplayContent);
Assert.AreEqual(1, result.Links.Count);
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
Assert.AreEqual(8, result.Links[0].Index);
Assert.AreEqual(23, result.Links[0].Length);
}
[Test]
public void TestMarkdownFormatWithBackslashes()
{
Message result = MessageFormatter.FormatMessage(new Message { Content = "This link [should end with a backslash \\](https://osu.ppy.sh)." });
Assert.AreEqual("This link should end with a backslash \\.", result.DisplayContent);
Assert.AreEqual(1, result.Links.Count);
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
Assert.AreEqual(10, result.Links[0].Index);
Assert.AreEqual(29, result.Links[0].Length);
}
[Test]
public void TestMarkdownFormatLinkWithEscapedAndBalancedBrackets()
{
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [\\]super\\[\\[ tricky [one]](https://osu.ppy.sh)!" });
Assert.AreEqual("This is a ]super[[ tricky [one]!", result.DisplayContent);
Assert.AreEqual(1, result.Links.Count);
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
Assert.AreEqual(10, result.Links[0].Index);
Assert.AreEqual(21, result.Links[0].Length);
}
[Test]
public void TestChannelLink()
{

View File

@ -5,6 +5,7 @@ using System;
using System.Globalization;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@ -134,6 +135,48 @@ namespace osu.Game.Tests.Visual.Gameplay
AddAssert("skinchanged only called once", () => consumer.SkinChangedCount == 1);
}
[Test]
public void TestSwitchOff()
{
SkinConsumer consumer = null;
SwitchableSkinProvidingContainer target = null;
AddStep("setup layout", () =>
{
Child = new SkinSourceContainer
{
RelativeSizeAxes = Axes.Both,
Child = target = new SwitchableSkinProvidingContainer(new SecondarySource())
{
RelativeSizeAxes = Axes.Both,
}
};
});
AddStep("add permissive", () => target.Add(consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation"), source => true)));
AddAssert("consumer using override source", () => consumer.Drawable is SecondarySourceBox);
AddStep("disable", () => target.Disable());
AddAssert("consumer using base source", () => consumer.Drawable is BaseSourceBox);
}
private class SwitchableSkinProvidingContainer : SkinProvidingContainer
{
private bool allow = true;
protected override bool AllowDrawableLookup(ISkinComponent component) => allow;
public void Disable()
{
allow = false;
TriggerSourceChanged();
}
public SwitchableSkinProvidingContainer(ISkin skin)
: base(skin)
{
}
}
private class ExposedSkinnableDrawable : SkinnableDrawable
{
public new Drawable Drawable => base.Drawable;
@ -272,7 +315,8 @@ namespace osu.Game.Tests.Visual.Gameplay
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
}
private class SkinSourceContainer : Container, ISkin
[Cached(typeof(ISkinSource))]
private class SkinSourceContainer : Container, ISkinSource
{
public Drawable GetDrawableComponent(ISkinComponent componentName) => new BaseSourceBox();
@ -281,6 +325,8 @@ namespace osu.Game.Tests.Visual.Gameplay
public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
public event Action SourceChanged;
}
private class TestSkinComponent : ISkinComponent

View File

@ -127,6 +127,9 @@ namespace osu.Game.Tests.Visual.Online
addMessageWithChecks("is now playing [https://osu.ppy.sh/b/252238 IMAGE -MATERIAL- <Version 0>]", 1, true, expectedActions: LinkAction.OpenBeatmap);
addMessageWithChecks("Let's (try)[https://osu.ppy.sh/home] [https://osu.ppy.sh/b/252238 multiple links] https://osu.ppy.sh/home", 3,
expectedActions: new[] { LinkAction.External, LinkAction.OpenBeatmap, LinkAction.External });
addMessageWithChecks("[https://osu.ppy.sh/home New link format with escaped [and \\[ paired] braces]", 1, expectedActions: LinkAction.External);
addMessageWithChecks("[Markdown link format with escaped [and \\[ paired] braces](https://osu.ppy.sh/home)", 1, expectedActions: LinkAction.External);
addMessageWithChecks("(Old link format with escaped (and \\( paired) parentheses)[https://osu.ppy.sh/home] and [[also a rogue wiki link]]", 2, expectedActions: new[] { LinkAction.External, LinkAction.External });
// note that there's 0 links here (they get removed if a channel is not found)
addMessageWithChecks("#lobby or #osu would be blue (and work) in the ChatDisplay test (when a proper ChatOverlay is present).");
addMessageWithChecks("I am important!", 0, false, true);

View File

@ -84,7 +84,7 @@ namespace osu.Game.Beatmaps.Drawables
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
// the null coalesce here is only present to make unit tests work (ruleset dlls aren't copied correctly for testing at the moment)
Icon = ruleset?.CreateInstance().CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle }
Icon = ruleset?.CreateInstance()?.CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle }
}
};
}

View File

@ -16,11 +16,11 @@ namespace osu.Game.Configuration
private readonly int? variant;
private readonly List<DatabasedSetting> databasedSettings;
private List<DatabasedSetting> databasedSettings;
private readonly RulesetInfo ruleset;
private readonly bool legacySettingsExist;
private bool legacySettingsExist;
protected DatabasedConfigManager(SettingsStore settings, RulesetInfo ruleset = null, int? variant = null)
{
@ -28,21 +28,31 @@ namespace osu.Game.Configuration
this.ruleset = ruleset;
this.variant = variant;
databasedSettings = settings.Query(ruleset?.ID, variant);
legacySettingsExist = databasedSettings.Any(s => int.TryParse(s.Key, out var _));
Load();
InitialiseDefaults();
}
protected override void PerformLoad()
{
databasedSettings = settings.Query(ruleset?.ID, variant);
legacySettingsExist = databasedSettings.Any(s => int.TryParse(s.Key, out var _));
}
protected override bool PerformSave()
{
lock (dirtySettings)
{
foreach (var setting in dirtySettings)
settings.Update(setting);
dirtySettings.Clear();
}
return true;
}
private readonly List<DatabasedSetting> dirtySettings = new List<DatabasedSetting>();
protected override void AddBindable<TBindable>(T lookup, Bindable<TBindable> bindable)
{
base.AddBindable(lookup, bindable);
@ -80,7 +90,12 @@ namespace osu.Game.Configuration
bindable.ValueChanged += b =>
{
setting.Value = b.NewValue;
settings.Update(setting);
lock (dirtySettings)
{
if (!dirtySettings.Contains(setting))
dirtySettings.Add(setting);
}
};
}
}

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace osu.Game.Online.Chat
@ -10,16 +11,16 @@ namespace osu.Game.Online.Chat
public static class MessageFormatter
{
// [[Performance Points]] -> wiki:Performance Points (https://osu.ppy.sh/wiki/Performance_Points)
private static readonly Regex wiki_regex = new Regex(@"\[\[([^\]]+)\]\]");
private static readonly Regex wiki_regex = new Regex(@"\[\[(?<text>[^\]]+)\]\]");
// (test)[https://osu.ppy.sh/b/1234] -> test (https://osu.ppy.sh/b/1234)
private static readonly Regex old_link_regex = new Regex(@"\(([^\)]*)\)\[([a-z]+://[^ ]+)\]");
private static readonly Regex old_link_regex = new Regex(@"\((?<text>(((?<=\\)[\(\)])|[^\(\)])*(((?<open>\()(((?<=\\)[\(\)])|[^\(\)])*)+((?<close-open>\))(((?<=\\)[\(\)])|[^\(\)])*)+)*(?(open)(?!)))\)\[(?<url>[a-z]+://[^ ]+)\]");
// [https://osu.ppy.sh/b/1234 Beatmap [Hard] (poop)] -> Beatmap [hard] (poop) (https://osu.ppy.sh/b/1234)
private static readonly Regex new_link_regex = new Regex(@"\[([a-z]+://[^ ]+) ([^\[\]]*(((?<open>\[)[^\[\]]*)+((?<close-open>\])[^\[\]]*)+)*(?(open)(?!)))\]");
private static readonly Regex new_link_regex = new Regex(@"\[(?<url>[a-z]+://[^ ]+) (?<text>(((?<=\\)[\[\]])|[^\[\]])*(((?<open>\[)(((?<=\\)[\[\]])|[^\[\]])*)+((?<close-open>\])(((?<=\\)[\[\]])|[^\[\]])*)+)*(?(open)(?!)))\]");
// [test](https://osu.ppy.sh/b/1234) -> test (https://osu.ppy.sh/b/1234) aka correct markdown format
private static readonly Regex markdown_link_regex = new Regex(@"\[([^\]]*)\]\(([a-z]+://[^ ]+)\)");
private static readonly Regex markdown_link_regex = new Regex(@"\[(?<text>(((?<=\\)[\[\]])|[^\[\]])*(((?<open>\[)(((?<=\\)[\[\]])|[^\[\]])*)+((?<close-open>\])(((?<=\\)[\[\]])|[^\[\]])*)+)*(?(open)(?!)))\]\((?<url>[a-z]+://[^ ]+)\)");
// advanced, RFC-compatible regular expression that matches any possible URL, *but* allows certain invalid characters that are widely used
// This is in the format (<required>, [optional]):
@ -48,7 +49,7 @@ namespace osu.Game.Online.Chat
// Unicode emojis
private static readonly Regex emoji_regex = new Regex(@"(\uD83D[\uDC00-\uDE4F])");
private static void handleMatches(Regex regex, string display, string link, MessageFormatterResult result, int startIndex = 0, LinkAction? linkActionOverride = null)
private static void handleMatches(Regex regex, string display, string link, MessageFormatterResult result, int startIndex = 0, LinkAction? linkActionOverride = null, char[] escapeChars = null)
{
int captureOffset = 0;
@ -58,16 +59,20 @@ namespace osu.Game.Online.Chat
var displayText = string.Format(display,
m.Groups[0],
m.Groups.Count > 1 ? m.Groups[1].Value : "",
m.Groups.Count > 2 ? m.Groups[2].Value : "").Trim();
m.Groups["text"].Value,
m.Groups["url"].Value).Trim();
var linkText = string.Format(link,
m.Groups[0],
m.Groups.Count > 1 ? m.Groups[1].Value : "",
m.Groups.Count > 2 ? m.Groups[2].Value : "").Trim();
m.Groups["text"].Value,
m.Groups["url"].Value).Trim();
if (displayText.Length == 0 || linkText.Length == 0) continue;
// Remove backslash escapes in front of the characters provided in escapeChars
if (escapeChars != null)
displayText = escapeChars.Aggregate(displayText, (current, c) => current.Replace($"\\{c}", c.ToString()));
// Check for encapsulated links
if (result.Links.Find(l => (l.Index <= index && l.Index + l.Length >= index + m.Length) || (index <= l.Index && index + m.Length >= l.Index + l.Length)) == null)
{
@ -183,13 +188,13 @@ namespace osu.Game.Online.Chat
var result = new MessageFormatterResult(toFormat);
// handle the [link display] format
handleMatches(new_link_regex, "{2}", "{1}", result, startIndex);
handleMatches(new_link_regex, "{1}", "{2}", result, startIndex, escapeChars: new[] { '[', ']' });
// handle the standard markdown []() format
handleMatches(markdown_link_regex, "{1}", "{2}", result, startIndex);
handleMatches(markdown_link_regex, "{1}", "{2}", result, startIndex, escapeChars: new[] { '[', ']' });
// handle the ()[] link format
handleMatches(old_link_regex, "{1}", "{2}", result, startIndex);
handleMatches(old_link_regex, "{1}", "{2}", result, startIndex, escapeChars: new[] { '(', ')' });
// handle wiki links
handleMatches(wiki_regex, "{1}", "https://osu.ppy.sh/wiki/{1}", result, startIndex);

View File

@ -7,6 +7,7 @@ using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Bindings;
using osu.Framework.IO.Stores;
using osu.Game.Beatmaps;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets.Edit;
@ -83,6 +84,8 @@ namespace osu.Game.Rulesets
public virtual Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.Solid.QuestionCircle };
public virtual IResourceStore<byte[]> CreateReourceStore() => new NamespacedResourceStore<byte[]>(new DllResourceStore(GetType().Assembly.Location), @"Resources");
public abstract string Description { get; }
public virtual RulesetSettingsSubsection CreateSettings() => null;

View File

@ -20,7 +20,12 @@ namespace osu.Game.Rulesets
[JsonIgnore]
public bool Available { get; set; }
public virtual Ruleset CreateInstance() => (Ruleset)Activator.CreateInstance(Type.GetType(InstantiationInfo), this);
public virtual Ruleset CreateInstance()
{
if (!Available) return null;
return (Ruleset)Activator.CreateInstance(Type.GetType(InstantiationInfo), this);
}
public bool Equals(RulesetInfo other) => other != null && ID == other.ID && Available == other.Available && Name == other.Name && InstantiationInfo == other.InstantiationInfo;

View File

@ -14,10 +14,14 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using JetBrains.Annotations;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input;
using osu.Framework.Input.Events;
using osu.Framework.IO.Stores;
using osu.Game.Configuration;
using osu.Game.Graphics.Cursor;
using osu.Game.Input.Handlers;
@ -51,6 +55,10 @@ namespace osu.Game.Rulesets.UI
private readonly Lazy<Playfield> playfield;
private TextureStore textureStore;
private ISampleStore sampleStore;
/// <summary>
/// The playfield.
/// </summary>
@ -142,6 +150,18 @@ namespace osu.Game.Rulesets.UI
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
var resources = Ruleset.CreateReourceStore();
if (resources != null)
{
textureStore = new TextureStore(new TextureLoaderStore(new NamespacedResourceStore<byte[]>(resources, "Textures")));
textureStore.AddStore(dependencies.Get<TextureStore>());
dependencies.Cache(textureStore);
sampleStore = dependencies.Get<AudioManager>().GetSampleStore(new NamespacedResourceStore<byte[]>(resources, "Samples"));
dependencies.CacheAs(sampleStore);
}
onScreenDisplay = dependencies.Get<OnScreenDisplay>();
Config = dependencies.Get<RulesetConfigCache>().GetConfigFor(Ruleset);

View File

@ -6,6 +6,7 @@ using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Game.Audio;
@ -20,7 +21,7 @@ namespace osu.Game.Skinning
private SampleChannel[] channels;
private AudioManager audio;
private ISampleStore samples;
public SkinnableSound(IEnumerable<ISampleInfo> hitSamples)
{
@ -33,9 +34,9 @@ namespace osu.Game.Skinning
}
[BackgroundDependencyLoader]
private void load(AudioManager audio)
private void load(ISampleStore samples)
{
this.audio = audio;
this.samples = samples;
}
private bool looping;
@ -81,7 +82,7 @@ namespace osu.Game.Skinning
if (ch == null && allowFallback)
foreach (var lookup in s.LookupNames)
if ((ch = audio.Samples.Get($"Gameplay/{lookup}")) != null)
if ((ch = samples.Get($"Gameplay/{lookup}")) != null)
break;
if (ch != null)
@ -102,8 +103,9 @@ namespace osu.Game.Skinning
{
base.Dispose(isDisposing);
foreach (var c in channels)
c.Dispose();
if (channels != null)
foreach (var c in channels)
c.Dispose();
}
}
}

View File

@ -64,5 +64,11 @@ namespace osu.Game.Storyboards.Drawables
LifetimeEnd = sampleInfo.StartTime;
}
}
protected override void Dispose(bool isDisposing)
{
channel?.Stop();
base.Dispose(isDisposing);
}
}
}

View File

@ -50,7 +50,11 @@ namespace osu.Game.Tests.Visual
Beatmap.Value = CreateWorkingBeatmap(beatmap);
if (!AllowFail)
Mods.Value = new[] { ruleset.GetAllMods().First(m => m is ModNoFail) };
{
var noFailMod = ruleset.GetAllMods().FirstOrDefault(m => m is ModNoFail);
if (noFailMod != null)
Mods.Value = new[] { noFailMod };
}
if (Autoplay)
{

View File

@ -6,6 +6,17 @@
<PlatformTarget>AnyCPU</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Label="Nuget">
<Title>osu!</Title>
<PackageId>ppy.osu.Game</PackageId>
<Authors>ppy Pty Ltd</Authors>
<PackageLicenseUrl>https://github.com/ppy/osu/blob/master/LICENCE.md</PackageLicenseUrl>
<PackageProjectUrl>https://github.com/ppy/osu</PackageProjectUrl>
<RepositoryUrl>https://github.com/ppy/osu</RepositoryUrl>
<PackageReleaseNotes>Automated release.</PackageReleaseNotes>
<copyright>Copyright (c) 2019 ppy Pty Ltd</copyright>
<PackageTags>osu game</PackageTags>
</PropertyGroup>
<ItemGroup Label="Service">
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>