1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-15 11:22:57 +08:00

Merge remote-tracking branch 'origin/master' into osu-default-bindings

This commit is contained in:
smoogipoo 2018-07-13 19:32:40 +09:00
commit 2d8e2dc5f7
77 changed files with 900 additions and 468 deletions

View File

@ -2,6 +2,9 @@ clone_depth: 1
version: '{branch}-{build}' version: '{branch}-{build}'
image: Visual Studio 2017 image: Visual Studio 2017
configuration: Debug configuration: Debug
cache:
- C:\ProgramData\chocolatey\bin -> appveyor.yml
- C:\ProgramData\chocolatey\lib -> appveyor.yml
install: install:
- cmd: git submodule update --init --recursive --depth=5 - cmd: git submodule update --init --recursive --depth=5
- cmd: choco install resharper-clt -y - cmd: choco install resharper-clt -y

View File

@ -12,6 +12,7 @@ using osu.Framework.Platform;
using osu.Game; using osu.Game;
using OpenTK.Input; using OpenTK.Input;
using Microsoft.Win32; using Microsoft.Win32;
using osu.Desktop.Updater;
using osu.Framework.Platform.Windows; using osu.Framework.Platform.Windows;
namespace osu.Desktop namespace osu.Desktop
@ -38,6 +39,52 @@ namespace osu.Desktop
} }
} }
protected override void LoadComplete()
{
base.LoadComplete();
if (!noVersionOverlay)
{
LoadComponentAsync(new VersionManager { Depth = int.MinValue }, v =>
{
Add(v);
v.State = Visibility.Visible;
});
#if NET_FRAMEWORK
Add(new SquirrelUpdateManager());
#else
Add(new SimpleUpdateManager());
#endif
}
}
public override void SetHost(GameHost host)
{
base.SetHost(host);
var desktopWindow = host.Window as DesktopGameWindow;
if (desktopWindow != null)
{
desktopWindow.CursorState |= CursorState.Hidden;
desktopWindow.SetIconFromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico"));
desktopWindow.Title = Name;
desktopWindow.FileDrop += fileDrop;
}
}
private void fileDrop(object sender, FileDropEventArgs e)
{
var filePaths = new[] { e.FileName };
var firstExtension = Path.GetExtension(filePaths.First());
if (filePaths.Any(f => Path.GetExtension(f) != firstExtension)) return;
Task.Factory.StartNew(() => Import(filePaths), TaskCreationOptions.LongRunning);
}
/// <summary> /// <summary>
/// A method of accessing an osu-stable install in a controlled fashion. /// A method of accessing an osu-stable install in a controlled fashion.
/// </summary> /// </summary>
@ -77,45 +124,5 @@ namespace osu.Desktop
{ {
} }
} }
protected override void LoadComplete()
{
base.LoadComplete();
if (!noVersionOverlay)
{
LoadComponentAsync(new VersionManager { Depth = int.MinValue }, v =>
{
Add(v);
v.State = Visibility.Visible;
});
}
}
public override void SetHost(GameHost host)
{
base.SetHost(host);
var desktopWindow = host.Window as DesktopGameWindow;
if (desktopWindow != null)
{
desktopWindow.CursorState |= CursorState.Hidden;
desktopWindow.SetIconFromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico"));
desktopWindow.Title = Name;
desktopWindow.FileDrop += fileDrop;
}
}
private void fileDrop(object sender, FileDropEventArgs e)
{
var filePaths = new[] { e.FileName };
var firstExtension = Path.GetExtension(filePaths.First());
if (filePaths.Any(f => Path.GetExtension(f) != firstExtension)) return;
Task.Factory.StartNew(() => Import(filePaths), TaskCreationOptions.LongRunning);
}
} }
} }

View File

@ -91,10 +91,6 @@ namespace osu.Desktop.Overlays
} }
} }
}; };
#if NET_FRAMEWORK
Add(new SquirrelUpdateManager());
#endif
} }
protected override void LoadComplete() protected override void LoadComplete()

View File

@ -7,6 +7,7 @@ using System.Linq;
using osu.Framework; using osu.Framework;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Game.IPC; using osu.Game.IPC;
#if NET_FRAMEWORK #if NET_FRAMEWORK
using System.Runtime; using System.Runtime;
#endif #endif
@ -18,10 +19,7 @@ namespace osu.Desktop
[STAThread] [STAThread]
public static int Main(string[] args) public static int Main(string[] args)
{ {
// required to initialise native SQLite libraries on some platforms. useMultiCoreJit();
if (!RuntimeInfo.IsMono)
useMulticoreJit();
// Back up the cwd before DesktopGameHost changes it // Back up the cwd before DesktopGameHost changes it
var cwd = Environment.CurrentDirectory; var cwd = Environment.CurrentDirectory;
@ -54,7 +52,7 @@ namespace osu.Desktop
} }
} }
private static void useMulticoreJit() private static void useMultiCoreJit()
{ {
#if NET_FRAMEWORK #if NET_FRAMEWORK
var directory = Directory.CreateDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Profiles")); var directory = Directory.CreateDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Profiles"));

View File

@ -0,0 +1,103 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Framework.IO.Network;
using osu.Framework.Platform;
using osu.Game;
using osu.Game.Graphics;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
namespace osu.Desktop.Updater
{
/// <summary>
/// An update manager that shows notifications if a newer release is detected.
/// Installation is left up to the user.
/// </summary>
internal class SimpleUpdateManager : CompositeDrawable
{
private NotificationOverlay notificationOverlay;
private string version;
private GameHost host;
[BackgroundDependencyLoader]
private void load(NotificationOverlay notification, OsuGameBase game, GameHost host)
{
notificationOverlay = notification;
this.host = host;
version = game.Version;
if (game.IsDeployedBuild)
Schedule(() => Task.Run(() => checkForUpdateAsync()));
}
private async void checkForUpdateAsync()
{
var releases = new JsonWebRequest<GitHubRelease>("https://api.github.com/repos/ppy/osu/releases/latest");
await releases.PerformAsync();
var latest = releases.ResponseObject;
if (latest.TagName != version)
{
notificationOverlay.Post(new SimpleNotification
{
Text = $"A newer release of osu! has been found ({version} → {latest.TagName}).\n\n"
+ "Click here to download the new version, which can be installed over the top of your existing installation",
Icon = FontAwesome.fa_upload,
Activated = () =>
{
host.OpenUrlExternally(getBestUrl(latest));
return true;
}
});
}
}
private string getBestUrl(GitHubRelease release)
{
GitHubAsset bestAsset = null;
switch (RuntimeInfo.OS)
{
case RuntimeInfo.Platform.Windows:
bestAsset = release.Assets?.FirstOrDefault(f => f.Name.EndsWith(".exe"));
break;
case RuntimeInfo.Platform.MacOsx:
bestAsset = release.Assets?.FirstOrDefault(f => f.Name.EndsWith(".app.zip"));
break;
}
return bestAsset?.BrowserDownloadUrl ?? release.HtmlUrl;
}
public class GitHubRelease
{
[JsonProperty("html_url")]
public string HtmlUrl { get; set; }
[JsonProperty("tag_name")]
public string TagName { get; set; }
[JsonProperty("assets")]
public List<GitHubAsset> Assets { get; set; }
}
public class GitHubAsset
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("browser_download_url")]
public string BrowserDownloadUrl { get; set; }
}
}
}

View File

@ -3,6 +3,7 @@
#if NET_FRAMEWORK #if NET_FRAMEWORK
using System; using System;
using System.Threading.Tasks;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
@ -16,7 +17,7 @@ using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using Squirrel; using Squirrel;
namespace osu.Desktop.Overlays namespace osu.Desktop.Updater
{ {
public class SquirrelUpdateManager : Component public class SquirrelUpdateManager : Component
{ {
@ -35,7 +36,7 @@ namespace osu.Desktop.Overlays
notificationOverlay = notification; notificationOverlay = notification;
if (game.IsDeployedBuild) if (game.IsDeployedBuild)
Schedule(() => checkForUpdateAsync()); Schedule(() => Task.Run(() => checkForUpdateAsync()));
} }
private async void checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification notification = null) private async void checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification notification = null)

View File

@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Catch.Tests
{ {
} }
public void ToggleHyperDash(bool status) => MovableCatcher.SetHyperdashState(status ? 2 : 1); public void ToggleHyperDash(bool status) => MovableCatcher.SetHyperDashState(status ? 2 : 1);
} }
} }
} }

View File

@ -8,9 +8,9 @@ using osu.Game.Rulesets.Catch.Objects;
namespace osu.Game.Rulesets.Catch.Tests namespace osu.Game.Rulesets.Catch.Tests
{ {
[TestFixture] [TestFixture]
public class TestCaseHyperdash : Game.Tests.Visual.TestCasePlayer public class TestCaseHyperDash : Game.Tests.Visual.TestCasePlayer
{ {
public TestCaseHyperdash() public TestCaseHyperDash()
: base(new CatchRuleset()) : base(new CatchRuleset())
{ {
} }

View File

@ -61,12 +61,12 @@ namespace osu.Game.Rulesets.Catch.Difficulty
return new CatchDifficultyAttributes(mods, 0); return new CatchDifficultyAttributes(mods, 0);
// this is the same as osu!, so there's potential to share the implementation... maybe // this is the same as osu!, so there's potential to share the implementation... maybe
double preEmpt = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate; double preempt = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate;
double starRating = Math.Sqrt(calculateDifficulty(difficultyHitObjects, timeRate)) * star_scaling_factor; double starRating = Math.Sqrt(calculateDifficulty(difficultyHitObjects, timeRate)) * star_scaling_factor;
return new CatchDifficultyAttributes(mods, starRating) return new CatchDifficultyAttributes(mods, starRating)
{ {
ApproachRate = preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0, ApproachRate = preempt > 1200.0 ? -(preempt - 1800.0) / 120.0 : -(preempt - 1200.0) / 150.0 + 5.0,
MaxCombo = difficultyHitObjects.Count MaxCombo = difficultyHitObjects.Count
}; };
} }

View File

@ -255,11 +255,11 @@ namespace osu.Game.Rulesets.Catch.UI
double positionDifference = target.X * CatchPlayfield.BASE_WIDTH - catcherPosition; double positionDifference = target.X * CatchPlayfield.BASE_WIDTH - catcherPosition;
double velocity = positionDifference / Math.Max(1.0, timeDifference - 1000.0 / 60.0); double velocity = positionDifference / Math.Max(1.0, timeDifference - 1000.0 / 60.0);
SetHyperdashState(Math.Abs(velocity), target.X); SetHyperDashState(Math.Abs(velocity), target.X);
} }
else else
{ {
SetHyperdashState(); SetHyperDashState();
} }
return validCatch; return validCatch;
@ -270,18 +270,18 @@ namespace osu.Game.Rulesets.Catch.UI
private float hyperDashTargetPosition; private float hyperDashTargetPosition;
/// <summary> /// <summary>
/// Whether we are hypderdashing or not. /// Whether we are hyper-dashing or not.
/// </summary> /// </summary>
public bool HyperDashing => hyperDashModifier != 1; public bool HyperDashing => hyperDashModifier != 1;
/// <summary> /// <summary>
/// Set hyperdash state. /// Set hyper-dash state.
/// </summary> /// </summary>
/// <param name="modifier">The speed multiplier. If this is less or equals to 1, this catcher will be non-hyperdashing state.</param> /// <param name="modifier">The speed multiplier. If this is less or equals to 1, this catcher will be non-hyper-dashing state.</param>
/// <param name="targetPosition">When this catcher crosses this position, this catcher ends hyperdashing.</param> /// <param name="targetPosition">When this catcher crosses this position, this catcher ends hyper-dashing.</param>
public void SetHyperdashState(double modifier = 1, float targetPosition = -1) public void SetHyperDashState(double modifier = 1, float targetPosition = -1)
{ {
const float hyperdash_transition_length = 180; const float hyper_dash_transition_length = 180;
bool previouslyHyperDashing = HyperDashing; bool previouslyHyperDashing = HyperDashing;
if (modifier <= 1 || X == targetPosition) if (modifier <= 1 || X == targetPosition)
@ -291,8 +291,8 @@ namespace osu.Game.Rulesets.Catch.UI
if (previouslyHyperDashing) if (previouslyHyperDashing)
{ {
this.FadeColour(Color4.White, hyperdash_transition_length, Easing.OutQuint); this.FadeColour(Color4.White, hyper_dash_transition_length, Easing.OutQuint);
this.FadeTo(1, hyperdash_transition_length, Easing.OutQuint); this.FadeTo(1, hyper_dash_transition_length, Easing.OutQuint);
} }
} }
else else
@ -303,8 +303,8 @@ namespace osu.Game.Rulesets.Catch.UI
if (!previouslyHyperDashing) if (!previouslyHyperDashing)
{ {
this.FadeColour(Color4.OrangeRed, hyperdash_transition_length, Easing.OutQuint); this.FadeColour(Color4.OrangeRed, hyper_dash_transition_length, Easing.OutQuint);
this.FadeTo(0.2f, hyperdash_transition_length, Easing.OutQuint); this.FadeTo(0.2f, hyper_dash_transition_length, Easing.OutQuint);
Trail = true; Trail = true;
} }
} }
@ -370,7 +370,7 @@ namespace osu.Game.Rulesets.Catch.UI
hyperDashDirection < 0 && hyperDashTargetPosition > X) hyperDashDirection < 0 && hyperDashTargetPosition > X)
{ {
X = hyperDashTargetPosition; X = hyperDashTargetPosition;
SetHyperdashState(); SetHyperDashState();
} }
} }

View File

@ -21,9 +21,9 @@ namespace osu.Game.Rulesets.Mania.Tests
this.direction = direction; this.direction = direction;
} }
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{ {
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.CacheAs<IScrollingInfo>(new ScrollingInfo { Direction = { Value = direction }}); dependencies.CacheAs<IScrollingInfo>(new ScrollingInfo { Direction = { Value = direction }});
return dependencies; return dependencies;
} }

View File

@ -137,9 +137,9 @@ namespace osu.Game.Rulesets.Mania.Tests
}; };
} }
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{ {
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.CacheAs<IBindable<ManiaAction>>(new Bindable<ManiaAction>()); dependencies.CacheAs<IBindable<ManiaAction>>(new Bindable<ManiaAction>());
return dependencies; return dependencies;
} }

View File

@ -19,9 +19,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, IBeatmap originalBeatmap) public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, IBeatmap originalBeatmap)
: base(random, hitObject, beatmap, new Pattern(), originalBeatmap) : base(random, hitObject, beatmap, new Pattern(), originalBeatmap)
{ {
var endtimeData = HitObject as IHasEndTime; endTime = (HitObject as IHasEndTime)?.EndTime ?? 0;
endTime = endtimeData?.EndTime ?? 0;
} }
public override IEnumerable<Pattern> Generate() public override IEnumerable<Pattern> Generate()

View File

@ -19,14 +19,14 @@ namespace osu.Game.Rulesets.Mania
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(ManiaConfigManager config) private void load()
{ {
Children = new Drawable[] Children = new Drawable[]
{ {
new SettingsEnumDropdown<ManiaScrollingDirection> new SettingsEnumDropdown<ManiaScrollingDirection>
{ {
LabelText = "Scrolling direction", LabelText = "Scrolling direction",
Bindable = config.GetBindable<ManiaScrollingDirection>(ManiaSetting.ScrollDirection) Bindable = ((ManiaConfigManager)Config).GetBindable<ManiaScrollingDirection>(ManiaSetting.ScrollDirection)
} }
}; };
} }

View File

@ -118,9 +118,9 @@ namespace osu.Game.Rulesets.Mania.UI
} }
} }
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{ {
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.CacheAs<IBindable<ManiaAction>>(Action); dependencies.CacheAs<IBindable<ManiaAction>>(Action);
return dependencies; return dependencies;
} }

View File

@ -70,19 +70,19 @@ namespace osu.Game.Rulesets.Mania.UI
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(ManiaConfigManager config) private void load()
{ {
BarLines.ForEach(Playfield.Add); BarLines.ForEach(Playfield.Add);
config.BindWith(ManiaSetting.ScrollDirection, configDirection); ((ManiaConfigManager)Config).BindWith(ManiaSetting.ScrollDirection, configDirection);
configDirection.BindValueChanged(d => scrollingInfo.Direction.Value = (ScrollingDirection)d, true); configDirection.BindValueChanged(d => scrollingInfo.Direction.Value = (ScrollingDirection)d, true);
} }
private DependencyContainer dependencies; private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{ {
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.CacheAs<IScrollingInfo>(scrollingInfo = new ScrollingInfo()); dependencies.CacheAs<IScrollingInfo>(scrollingInfo = new ScrollingInfo());
return dependencies; return dependencies;
} }

View File

@ -54,7 +54,7 @@ namespace osu.Game.Rulesets.Osu.Tests
public struct ConvertValue : IEquatable<ConvertValue> public struct ConvertValue : IEquatable<ConvertValue>
{ {
/// <summary> /// <summary>
/// A sane value to account for osu!stable using ints everwhere. /// A sane value to account for osu!stable using <see cref="int"/>s everywhere.
/// </summary> /// </summary>
private const double conversion_lenience = 2; private const double conversion_lenience = 2;

View File

@ -61,19 +61,19 @@ namespace osu.Game.Rulesets.Osu.Difficulty
double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier; double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2; double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2;
// Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future // Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be removed in the future
double hitWindowGreat = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / timeRate; double hitWindowGreat = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / timeRate;
double preEmpt = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate; double preempt = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate;
int maxCombo = beatmap.HitObjects.Count(); int maxCombo = beatmap.HitObjects.Count();
// Add the ticks + tail of the slider. 1 is subtracted because the "headcircle" would be counted twice (once for the slider itself in the line above) // Add the ticks + tail of the slider. 1 is subtracted because the head circle would be counted twice (once for the slider itself in the line above)
maxCombo += beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1); maxCombo += beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
return new OsuDifficultyAttributes(mods, starRating) return new OsuDifficultyAttributes(mods, starRating)
{ {
AimStrain = aimRating, AimStrain = aimRating,
SpeedStrain = speedRating, SpeedStrain = speedRating,
ApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5, ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
OverallDifficulty = (80 - hitWindowGreat) / 6, OverallDifficulty = (80 - hitWindowGreat) / 6,
MaxCombo = maxCombo MaxCombo = maxCombo
}; };

View File

@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables) public override void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables)
{ {
void adjustFadeIn(OsuHitObject h) => h.TimeFadein = h.TimePreempt * fade_in_duration_multiplier; void adjustFadeIn(OsuHitObject h) => h.TimeFadeIn = h.TimePreempt * fade_in_duration_multiplier;
foreach (var d in drawables.OfType<DrawableOsuHitObject>()) foreach (var d in drawables.OfType<DrawableOsuHitObject>())
{ {
@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.Mods
var h = d.HitObject; var h = d.HitObject;
var fadeOutStartTime = h.StartTime - h.TimePreempt + h.TimeFadein; var fadeOutStartTime = h.StartTime - h.TimePreempt + h.TimeFadeIn;
var fadeOutDuration = h.TimePreempt * fade_out_duration_multiplier; var fadeOutDuration = h.TimePreempt * fade_out_duration_multiplier;
// new duration from completed fade in to end (before fading out) // new duration from completed fade in to end (before fading out)

View File

@ -96,12 +96,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
using (fp.BeginAbsoluteSequence(fadeInTime)) using (fp.BeginAbsoluteSequence(fadeInTime))
{ {
fp.FadeIn(currHitObject.TimeFadein); fp.FadeIn(currHitObject.TimeFadeIn);
fp.ScaleTo(1, currHitObject.TimeFadein, Easing.Out); fp.ScaleTo(1, currHitObject.TimeFadeIn, Easing.Out);
fp.MoveTo(pointEndPosition, currHitObject.TimeFadein, Easing.Out); fp.MoveTo(pointEndPosition, currHitObject.TimeFadeIn, Easing.Out);
fp.Delay(fadeOutTime - fadeInTime).FadeOut(currHitObject.TimeFadein); fp.Delay(fadeOutTime - fadeInTime).FadeOut(currHitObject.TimeFadeIn);
} }
fp.Expire(true); fp.Expire(true);

View File

@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
base.UpdatePreemptState(); base.UpdatePreemptState();
ApproachCircle.FadeIn(Math.Min(HitObject.TimeFadein * 2, HitObject.TimePreempt)); ApproachCircle.FadeIn(Math.Min(HitObject.TimeFadeIn * 2, HitObject.TimePreempt));
ApproachCircle.ScaleTo(1.1f, HitObject.TimePreempt); ApproachCircle.ScaleTo(1.1f, HitObject.TimePreempt);
} }

View File

@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
AccentColour = skin.GetValue<SkinConfiguration, Color4>(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White; AccentColour = skin.GetValue<SkinConfiguration, Color4>(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
} }
protected virtual void UpdatePreemptState() => this.FadeIn(HitObject.TimeFadein); protected virtual void UpdatePreemptState() => this.FadeIn(HitObject.TimeFadeIn);
protected virtual void UpdateCurrentState(ArmedState state) protected virtual void UpdateCurrentState(ArmedState state)
{ {

View File

@ -167,7 +167,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
Disc.Tracking = OsuActionInputManager.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton); Disc.Tracking = OsuActionInputManager.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton);
if (!spmCounter.IsPresent && Disc.Tracking) if (!spmCounter.IsPresent && Disc.Tracking)
spmCounter.FadeIn(HitObject.TimeFadein); spmCounter.FadeIn(HitObject.TimeFadeIn);
base.Update(); base.Update();
} }

View File

@ -212,7 +212,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
var spanProgress = slider.ProgressAt(completionProgress); var spanProgress = slider.ProgressAt(completionProgress);
double start = 0; double start = 0;
double end = SnakingIn ? MathHelper.Clamp((Time.Current - (slider.StartTime - slider.TimePreempt)) / slider.TimeFadein, 0, 1) : 1; double end = SnakingIn ? MathHelper.Clamp((Time.Current - (slider.StartTime - slider.TimePreempt)) / slider.TimeFadeIn, 0, 1) : 1;
if (span >= slider.SpanCount() - 1) if (span >= slider.SpanCount() - 1)
{ {

View File

@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Objects
public event Action<Vector2> PositionChanged; public event Action<Vector2> PositionChanged;
public double TimePreempt = 600; public double TimePreempt = 600;
public double TimeFadein = 400; public double TimeFadeIn = 400;
private Vector2 position; private Vector2 position;
@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Osu.Objects
base.ApplyDefaultsToSelf(controlPointInfo, difficulty); base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
TimePreempt = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450); TimePreempt = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450);
TimeFadein = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1200, 800, 300); TimeFadeIn = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1200, 800, 300);
Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2; Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2;
} }

View File

@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects
// This is so on repeats ticks don't appear too late to be visually processed by the player. // This is so on repeats ticks don't appear too late to be visually processed by the player.
offset = 200; offset = 200;
else else
offset = TimeFadein * 0.66f; offset = TimeFadeIn * 0.66f;
TimePreempt = (StartTime - SpanStartTime) / 2 + offset; TimePreempt = (StartTime - SpanStartTime) / 2 + offset;
} }

View File

@ -222,10 +222,10 @@ namespace osu.Game.Tests.Beatmaps.Formats
{ {
var hitObjects = decoder.Decode(stream).HitObjects; var hitObjects = decoder.Decode(stream).HitObjects;
Assert.AreEqual("hitnormal", getTestableSampleInfo(hitObjects[0]).Name); Assert.AreEqual("normal-hitnormal", getTestableSampleInfo(hitObjects[0]).LookupNames.First());
Assert.AreEqual("hitnormal", getTestableSampleInfo(hitObjects[1]).Name); Assert.AreEqual("normal-hitnormal", getTestableSampleInfo(hitObjects[1]).LookupNames.First());
Assert.AreEqual("hitnormal2", getTestableSampleInfo(hitObjects[2]).Name); Assert.AreEqual("normal-hitnormal2", getTestableSampleInfo(hitObjects[2]).LookupNames.First());
Assert.AreEqual("hitnormal", getTestableSampleInfo(hitObjects[3]).Name); Assert.AreEqual("normal-hitnormal", getTestableSampleInfo(hitObjects[3]).LookupNames.First());
} }
SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(new SampleInfo { Name = "hitnormal" }); SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(new SampleInfo { Name = "hitnormal" });
@ -242,7 +242,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.AreEqual("hit_1.wav", hitObjects[0].Samples[0].LookupNames.First()); Assert.AreEqual("hit_1.wav", hitObjects[0].Samples[0].LookupNames.First());
Assert.AreEqual("hit_2.wav", hitObjects[1].Samples[0].LookupNames.First()); Assert.AreEqual("hit_2.wav", hitObjects[1].Samples[0].LookupNames.First());
Assert.AreEqual("hitnormal2", getTestableSampleInfo(hitObjects[2]).Name); Assert.AreEqual("normal-hitnormal2", getTestableSampleInfo(hitObjects[2]).LookupNames.First());
Assert.AreEqual("hit_1.wav", hitObjects[3].Samples[0].LookupNames.First()); Assert.AreEqual("hit_1.wav", hitObjects[3].Samples[0].LookupNames.First());
} }

View File

@ -110,8 +110,8 @@ namespace osu.Game.Tests.Visual
private void testInfoLabels(int expectedCount) private void testInfoLabels(int expectedCount)
{ {
AddAssert("check infolabels exists", () => infoWedge.Info.InfoLabelContainer.Children.Any()); AddAssert("check info labels exists", () => infoWedge.Info.InfoLabelContainer.Children.Any());
AddAssert("check infolabels count", () => infoWedge.Info.InfoLabelContainer.Children.Count == expectedCount); AddAssert("check info labels count", () => infoWedge.Info.InfoLabelContainer.Children.Count == expectedCount);
} }
private void testNullBeatmap() private void testNullBeatmap()
@ -121,7 +121,7 @@ namespace osu.Game.Tests.Visual
AddAssert("check default title", () => infoWedge.Info.TitleLabel.Text == Beatmap.Default.BeatmapInfo.Metadata.Title); AddAssert("check default title", () => infoWedge.Info.TitleLabel.Text == Beatmap.Default.BeatmapInfo.Metadata.Title);
AddAssert("check default artist", () => infoWedge.Info.ArtistLabel.Text == Beatmap.Default.BeatmapInfo.Metadata.Artist); AddAssert("check default artist", () => infoWedge.Info.ArtistLabel.Text == Beatmap.Default.BeatmapInfo.Metadata.Artist);
AddAssert("check empty author", () => !infoWedge.Info.MapperContainer.Children.Any()); AddAssert("check empty author", () => !infoWedge.Info.MapperContainer.Children.Any());
AddAssert("check no infolabels", () => !infoWedge.Info.InfoLabelContainer.Children.Any()); AddAssert("check no info labels", () => !infoWedge.Info.InfoLabelContainer.Children.Any());
} }
private void selectBeatmap(IBeatmap b) private void selectBeatmap(IBeatmap b)

View File

@ -1,6 +1,9 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
@ -13,6 +16,13 @@ namespace osu.Game.Tests.Visual
[TestFixture] [TestFixture]
public class TestCaseButtonSystem : OsuTestCase public class TestCaseButtonSystem : OsuTestCase
{ {
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(ButtonSystem),
typeof(ButtonArea),
typeof(Button)
};
public TestCaseButtonSystem() public TestCaseButtonSystem()
{ {
OsuLogo logo; OsuLogo logo;
@ -30,6 +40,9 @@ namespace osu.Game.Tests.Visual
}; };
buttons.SetOsuLogo(logo); buttons.SetOsuLogo(logo);
foreach (var s in Enum.GetValues(typeof(ButtonSystemState)).OfType<ButtonSystemState>().Skip(1))
AddStep($"State to {s}", () => buttons.State = s);
} }
} }
} }

View File

@ -0,0 +1,28 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Game.Screens.Menu;
using OpenTK.Graphics;
namespace osu.Game.Tests.Visual
{
public class TestCaseDisclaimer : OsuTestCase
{
[BackgroundDependencyLoader]
private void load()
{
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
},
new Disclaimer()
};
}
}
}

View File

@ -114,7 +114,7 @@ namespace osu.Game.Tests.Visual
testMultiplierTextColour(noFailMod, modSelect.LowMultiplierColour); testMultiplierTextColour(noFailMod, modSelect.LowMultiplierColour);
testMultiplierTextColour(hiddenMod, modSelect.HighMultiplierColour); testMultiplierTextColour(hiddenMod, modSelect.HighMultiplierColour);
testUnimplmentedMod(autoPilotMod); testUnimplementedMod(autoPilotMod);
} }
private void testManiaMods(ManiaRuleset ruleset) private void testManiaMods(ManiaRuleset ruleset)
@ -154,7 +154,7 @@ namespace osu.Game.Tests.Visual
checkNotSelected(mod); checkNotSelected(mod);
} }
private void testUnimplmentedMod(Mod mod) private void testUnimplementedMod(Mod mod)
{ {
selectNext(mod); selectNext(mod);
checkNotSelected(mod); checkNotSelected(mod);

View File

@ -88,7 +88,7 @@ namespace osu.Game.Tests.Visual
private class TestOnScreenDisplay : OnScreenDisplay private class TestOnScreenDisplay : OnScreenDisplay
{ {
protected override void Display(Drawable toDisplay) => toDisplay.FadeIn().ResizeHeightTo(110); protected override void DisplayTemporarily(Drawable toDisplay) => toDisplay.FadeIn().ResizeHeightTo(110);
} }
} }
} }

View File

@ -6,7 +6,6 @@ using System.Collections.Generic;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Timing;
using osu.Game.Screens; using osu.Game.Screens;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
using OpenTK.Graphics; using OpenTK.Graphics;
@ -23,19 +22,15 @@ namespace osu.Game.Tests.Visual
public TestCaseOsuGame() public TestCaseOsuGame()
{ {
var rateAdjustClock = new StopwatchClock(true); Children = new Drawable[]
var framedClock = new FramedClock(rateAdjustClock);
framedClock.ProcessFrame();
Add(new Box
{ {
RelativeSizeAxes = Axes.Both, new Box
Colour = Color4.Black, {
}); RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
Add(new Loader()); },
new Loader()
AddSliderStep("Playback speed", 0.0, 2.0, 1, v => rateAdjustClock.Rate = v); };
} }
} }
} }

View File

@ -14,9 +14,9 @@ namespace osu.Game.Tests.Visual
{ {
private readonly PreviewTrackManager trackManager = new TestPreviewTrackManager(); private readonly PreviewTrackManager trackManager = new TestPreviewTrackManager();
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{ {
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.CacheAs(trackManager); dependencies.CacheAs(trackManager);
dependencies.CacheAs<IPreviewTrackOwner>(this); dependencies.CacheAs<IPreviewTrackOwner>(this);
return dependencies; return dependencies;
@ -101,9 +101,9 @@ namespace osu.Game.Tests.Visual
AddInternal(track); AddInternal(track);
} }
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{ {
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.CacheAs<IPreviewTrackOwner>(this); dependencies.CacheAs<IPreviewTrackOwner>(this);
return dependencies; return dependencies;
} }

View File

@ -16,8 +16,8 @@ namespace osu.Game.Tests.Visual
public override IReadOnlyList<Type> RequiredTypes => new[] public override IReadOnlyList<Type> RequiredTypes => new[]
{ {
typeof(ToolbarButton), typeof(ToolbarButton),
typeof(ToolbarModeSelector), typeof(ToolbarRulesetSelector),
typeof(ToolbarModeButton), typeof(ToolbarRulesetButton),
typeof(ToolbarNotificationButton), typeof(ToolbarNotificationButton),
}; };

View File

@ -53,7 +53,6 @@ namespace osu.Game.Tests.Visual
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c1.jpg", CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c1.jpg",
JoinDate = DateTimeOffset.Now.AddDays(-1), JoinDate = DateTimeOffset.Now.AddDays(-1),
LastVisit = DateTimeOffset.Now, LastVisit = DateTimeOffset.Now,
Age = 1,
ProfileOrder = new[] { "me" }, ProfileOrder = new[] { "me" },
Statistics = new UserStatistics Statistics = new UserStatistics
{ {

View File

@ -29,6 +29,11 @@ namespace osu.Game.Audio
/// </summary> /// </summary>
public string Name; public string Name;
/// <summary>
/// An optional suffix to provide priority lookup. Falls back to non-suffixed <see cref="Name"/>.
/// </summary>
public string Suffix;
/// <summary> /// <summary>
/// The sample volume. /// The sample volume.
/// </summary> /// </summary>
@ -42,9 +47,16 @@ namespace osu.Game.Audio
get get
{ {
if (!string.IsNullOrEmpty(Namespace)) if (!string.IsNullOrEmpty(Namespace))
{
if (!string.IsNullOrEmpty(Suffix))
yield return $"{Namespace}/{Bank}-{Name}{Suffix}";
yield return $"{Namespace}/{Bank}-{Name}"; yield return $"{Namespace}/{Bank}-{Name}";
}
yield return $"{Bank}-{Name}"; // Without namespace as a fallback even when we have a namespace // check non-namespace as a fallback even when we have a namespace
if (!string.IsNullOrEmpty(Suffix))
yield return $"{Bank}-{Name}{Suffix}";
yield return $"{Bank}-{Name}";
} }
} }

View File

@ -92,7 +92,7 @@ namespace osu.Game.Beatmaps
// by setting the model here, we can update the noline set id below. // by setting the model here, we can update the noline set id below.
b.BeatmapSet = model; b.BeatmapSet = model;
fetchAndPopulateOnlineIDs(b); fetchAndPopulateOnlineIDs(b, model.Beatmaps);
} }
// check if a set already exists with the same online id, delete if it does. // check if a set already exists with the same online id, delete if it does.
@ -339,6 +339,8 @@ namespace osu.Game.Beatmaps
{ {
var beatmapInfos = new List<BeatmapInfo>(); var beatmapInfos = new List<BeatmapInfo>();
bool invalidateOnlineIDs = false;
foreach (var name in reader.Filenames.Where(f => f.EndsWith(".osu"))) foreach (var name in reader.Filenames.Where(f => f.EndsWith(".osu")))
{ {
using (var raw = reader.GetStream(name)) using (var raw = reader.GetStream(name))
@ -355,9 +357,18 @@ namespace osu.Game.Beatmaps
beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash(); beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash();
beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash(); beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash();
// check that no existing beatmap exists that is imported with the same online beatmap ID. if so, give it precedence. if (beatmap.BeatmapInfo.OnlineBeatmapID.HasValue)
if (beatmap.BeatmapInfo.OnlineBeatmapID.HasValue && QueryBeatmap(b => b.OnlineBeatmapID.Value == beatmap.BeatmapInfo.OnlineBeatmapID.Value) != null) {
beatmap.BeatmapInfo.OnlineBeatmapID = null; var ourId = beatmap.BeatmapInfo.OnlineBeatmapID;
// check that no existing beatmap in database exists that is imported with the same online beatmap ID. if so, give it precedence.
if (QueryBeatmap(b => b.OnlineBeatmapID.Value == ourId) != null)
beatmap.BeatmapInfo.OnlineBeatmapID = null;
// check that no other beatmap in this imported set has a conflicting online beatmap ID. If so, presume *all* are incorrect.
if (beatmapInfos.Any(b => b.OnlineBeatmapID == ourId))
invalidateOnlineIDs = true;
}
RulesetInfo ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID); RulesetInfo ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID);
@ -375,6 +386,9 @@ namespace osu.Game.Beatmaps
} }
} }
if (invalidateOnlineIDs)
beatmapInfos.ForEach(b => b.OnlineBeatmapID = null);
return beatmapInfos; return beatmapInfos;
} }
@ -382,9 +396,10 @@ namespace osu.Game.Beatmaps
/// Query the API to populate mising OnlineBeatmapID / OnlineBeatmapSetID properties. /// Query the API to populate mising OnlineBeatmapID / OnlineBeatmapSetID properties.
/// </summary> /// </summary>
/// <param name="beatmap">The beatmap to populate.</param> /// <param name="beatmap">The beatmap to populate.</param>
/// <param name="otherBeatmaps">The other beatmaps contained within this set.</param>
/// <param name="force">Whether to re-query if the provided beatmap already has populated values.</param> /// <param name="force">Whether to re-query if the provided beatmap already has populated values.</param>
/// <returns>True if population was successful.</returns> /// <returns>True if population was successful.</returns>
private bool fetchAndPopulateOnlineIDs(BeatmapInfo beatmap, bool force = false) private bool fetchAndPopulateOnlineIDs(BeatmapInfo beatmap, IEnumerable<BeatmapInfo> otherBeatmaps, bool force = false)
{ {
if (!force && beatmap.OnlineBeatmapID != null && beatmap.BeatmapSet.OnlineBeatmapSetID != null) if (!force && beatmap.OnlineBeatmapID != null && beatmap.BeatmapSet.OnlineBeatmapSetID != null)
return true; return true;
@ -404,6 +419,12 @@ namespace osu.Game.Beatmaps
Logger.Log($"Successfully mapped to {res.OnlineBeatmapSetID} / {res.OnlineBeatmapID}.", LoggingTarget.Database); Logger.Log($"Successfully mapped to {res.OnlineBeatmapSetID} / {res.OnlineBeatmapID}.", LoggingTarget.Database);
if (otherBeatmaps.Any(b => b.OnlineBeatmapID == res.OnlineBeatmapID))
{
Logger.Log("Another beatmap in the same set already mapped to this ID. We'll skip adding it this time.", LoggingTarget.Database);
return false;
}
beatmap.BeatmapSet.OnlineBeatmapSetID = res.OnlineBeatmapSetID; beatmap.BeatmapSet.OnlineBeatmapSetID = res.OnlineBeatmapSetID;
beatmap.OnlineBeatmapID = res.OnlineBeatmapID; beatmap.OnlineBeatmapID = res.OnlineBeatmapID;
return true; return true;

View File

@ -14,7 +14,6 @@ namespace osu.Game.Beatmaps
public class BeatmapMetadata : IEquatable<BeatmapMetadata> public class BeatmapMetadata : IEquatable<BeatmapMetadata>
{ {
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[JsonIgnore]
public int ID { get; set; } public int ID { get; set; }
public string Title { get; set; } public string Title { get; set; }

View File

@ -9,14 +9,14 @@ using OpenTK.Graphics;
namespace osu.Game.Beatmaps.Drawables namespace osu.Game.Beatmaps.Drawables
{ {
public class DifficultyColouredContainer : Container, IHasAccentColour public abstract class DifficultyColouredContainer : Container, IHasAccentColour
{ {
public Color4 AccentColour { get; set; } public Color4 AccentColour { get; set; }
private readonly BeatmapInfo beatmap; private readonly BeatmapInfo beatmap;
private OsuColour palette; private OsuColour palette;
public DifficultyColouredContainer(BeatmapInfo beatmap) protected DifficultyColouredContainer(BeatmapInfo beatmap)
{ {
this.beatmap = beatmap; this.beatmap = beatmap;
} }

View File

@ -3,10 +3,14 @@
using System; using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using OpenTK; using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Beatmaps.Drawables namespace osu.Game.Beatmaps.Drawables
{ {
@ -14,7 +18,8 @@ namespace osu.Game.Beatmaps.Drawables
{ {
private readonly BeatmapInfo beatmap; private readonly BeatmapInfo beatmap;
public DifficultyIcon(BeatmapInfo beatmap) : base(beatmap) public DifficultyIcon(BeatmapInfo beatmap)
: base(beatmap)
{ {
if (beatmap == null) if (beatmap == null)
throw new ArgumentNullException(nameof(beatmap)); throw new ArgumentNullException(nameof(beatmap));
@ -28,16 +33,29 @@ namespace osu.Game.Beatmaps.Drawables
{ {
Children = new Drawable[] Children = new Drawable[]
{ {
new SpriteIcon new CircularContainer
{ {
RelativeSizeAxes = Axes.Both,
Scale = new Vector2(0.84f),
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both, Masking = true,
Colour = AccentColour, EdgeEffect = new EdgeEffectParameters
Icon = FontAwesome.fa_circle {
Colour = Color4.Black.Opacity(0.08f),
Type = EdgeEffectType.Shadow,
Radius = 5,
},
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = AccentColour,
},
}, },
new ConstrainedIconContainer new ConstrainedIconContainer
{ {
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both, 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) // the null coalesce here is only present to make unit tests work (ruleset dlls aren't copied correctly for testing at the moment)
Icon = beatmap.Ruleset?.CreateInstance().CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.fa_question_circle_o } Icon = beatmap.Ruleset?.CreateInstance().CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.fa_question_circle_o }

View File

@ -179,7 +179,7 @@ namespace osu.Game.Beatmaps.Formats
var baseInfo = base.ApplyTo(sampleInfo); var baseInfo = base.ApplyTo(sampleInfo);
if (CustomSampleBank > 1) if (CustomSampleBank > 1)
baseInfo.Name += CustomSampleBank; baseInfo.Suffix = CustomSampleBank.ToString();
return baseInfo; return baseInfo;
} }

View File

@ -26,9 +26,9 @@ namespace osu.Game.Graphics.Containers
protected readonly Bindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>(OverlayActivation.All); protected readonly Bindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>(OverlayActivation.All);
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{ {
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.CacheAs<IPreviewTrackOwner>(this); dependencies.CacheAs<IPreviewTrackOwner>(this);
return dependencies; return dependencies;
} }

View File

@ -21,6 +21,8 @@ namespace osu.Game.Graphics.Cursor
{ {
} }
protected override double AppearDelay => (1 - CurrentTooltip.Alpha) * base.AppearDelay; // reduce appear delay if the tooltip is already partly visible.
public class OsuTooltip : Tooltip public class OsuTooltip : Tooltip
{ {
private readonly Box background; private readonly Box background;

View File

@ -63,7 +63,14 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"beatmapset")] [JsonProperty(@"beatmapset")]
private BeatmapMetadata metadata private BeatmapMetadata metadata
{ {
set => Beatmap.Metadata = value; set
{
// extract the set ID to its correct place.
Beatmap.BeatmapSet = new BeatmapSetInfo { OnlineBeatmapSetID = value.ID };
value.ID = 0;
Beatmap.Metadata = value;
}
} }
[JsonProperty(@"statistics")] [JsonProperty(@"statistics")]

View File

@ -122,8 +122,8 @@ namespace osu.Game
private DependencyContainer dependencies; private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) =>
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(FrameworkConfigManager frameworkConfig) private void load(FrameworkConfigManager frameworkConfig)

View File

@ -20,6 +20,7 @@ using osu.Game.Graphics.Cursor;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Framework.Graphics.Performance; using osu.Framework.Graphics.Performance;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Framework.Input;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Game.Audio; using osu.Game.Audio;
using osu.Game.Database; using osu.Game.Database;
@ -30,6 +31,7 @@ using osu.Game.IO;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Skinning; using osu.Game.Skinning;
using OpenTK.Input;
using DebugUtils = osu.Game.Utils.DebugUtils; using DebugUtils = osu.Game.Utils.DebugUtils;
namespace osu.Game namespace osu.Game
@ -93,11 +95,13 @@ namespace osu.Game
private DependencyContainer dependencies; private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) =>
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
private DatabaseContextFactory contextFactory; private DatabaseContextFactory contextFactory;
protected override UserInputManager CreateUserInputManager() => new OsuUserInputManager();
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
@ -267,5 +271,31 @@ namespace osu.Game
return copy; return copy;
} }
} }
private class OsuUserInputManager : UserInputManager
{
protected override MouseButtonEventManager CreateButtonManagerFor(MouseButton button)
{
switch (button)
{
case MouseButton.Right:
return new RightMouseManager(button);
}
return base.CreateButtonManagerFor(button);
}
private class RightMouseManager : MouseButtonEventManager
{
public RightMouseManager(MouseButton button)
: base(button)
{
}
public override bool EnableDrag => true; // allow right-mouse dragging for absolute scroll in scroll containers.
public override bool EnableClick => false;
public override bool ChangeFocusOnClick => false;
}
}
} }
} }

View File

@ -102,6 +102,7 @@ namespace osu.Game.Overlays.KeyBinding
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
Margin = new MarginPadding(padding), Margin = new MarginPadding(padding),
Padding = new MarginPadding { Top = height },
Alpha = 0, Alpha = 0,
Colour = colours.YellowDark Colour = colours.YellowDark
} }
@ -267,7 +268,7 @@ namespace osu.Game.Overlays.KeyBinding
GetContainingInputManager().ChangeFocus(null); GetContainingInputManager().ChangeFocus(null);
pressAKey.FadeOut(300, Easing.OutQuint); pressAKey.FadeOut(300, Easing.OutQuint);
pressAKey.Padding = new MarginPadding { Top = height, Bottom = -pressAKey.DrawHeight }; pressAKey.BypassAutoSizeAxes |= Axes.Y;
} }
protected override void OnFocus(InputState state) protected override void OnFocus(InputState state)
@ -276,7 +277,7 @@ namespace osu.Game.Overlays.KeyBinding
AutoSizeEasing = Easing.OutQuint; AutoSizeEasing = Easing.OutQuint;
pressAKey.FadeIn(300, Easing.OutQuint); pressAKey.FadeIn(300, Easing.OutQuint);
pressAKey.Padding = new MarginPadding { Top = height }; pressAKey.BypassAutoSizeAxes &= ~Axes.Y;
updateBindTarget(); updateBindTarget();
base.OnFocus(state); base.OnFocus(state);

View File

@ -14,6 +14,8 @@ using osu.Game.Graphics;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics.Transforms;
using osu.Framework.Threading;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
@ -135,7 +137,7 @@ namespace osu.Game.Overlays
/// <exception cref="InvalidOperationException">If <paramref name="configManager"/> is already being tracked from the same <paramref name="source"/>.</exception> /// <exception cref="InvalidOperationException">If <paramref name="configManager"/> is already being tracked from the same <paramref name="source"/>.</exception>
public void BeginTracking(object source, ITrackableConfigManager configManager) public void BeginTracking(object source, ITrackableConfigManager configManager)
{ {
if (configManager == null) throw new ArgumentNullException(nameof(configManager)); if (configManager == null) throw new ArgumentNullException(nameof(configManager));
if (trackedConfigManagers.ContainsKey((source, configManager))) if (trackedConfigManagers.ContainsKey((source, configManager)))
throw new InvalidOperationException($"{nameof(configManager)} is already registered."); throw new InvalidOperationException($"{nameof(configManager)} is already registered.");
@ -159,7 +161,7 @@ namespace osu.Game.Overlays
/// <exception cref="InvalidOperationException">If <paramref name="configManager"/> is not being tracked from the same <see cref="source"/>.</exception> /// <exception cref="InvalidOperationException">If <paramref name="configManager"/> is not being tracked from the same <see cref="source"/>.</exception>
public void StopTracking(object source, ITrackableConfigManager configManager) public void StopTracking(object source, ITrackableConfigManager configManager)
{ {
if (configManager == null) throw new ArgumentNullException(nameof(configManager)); if (configManager == null) throw new ArgumentNullException(nameof(configManager));
if (!trackedConfigManagers.TryGetValue((source, configManager), out var existing)) if (!trackedConfigManagers.TryGetValue((source, configManager), out var existing))
throw new InvalidOperationException($"{nameof(configManager)} is not registered."); throw new InvalidOperationException($"{nameof(configManager)} is not registered.");
@ -181,7 +183,7 @@ namespace osu.Game.Overlays
if (string.IsNullOrEmpty(textLine3.Text)) if (string.IsNullOrEmpty(textLine3.Text))
textLine3.Text = "NO KEY BOUND"; textLine3.Text = "NO KEY BOUND";
Display(box); DisplayTemporarily(box);
int optionCount = 0; int optionCount = 0;
int selectedOption = -1; int selectedOption = -1;
@ -213,15 +215,29 @@ namespace osu.Game.Overlays
}); });
} }
protected virtual void Display(Drawable toDisplay) private TransformSequence<Drawable> fadeIn;
private ScheduledDelegate fadeOut;
protected virtual void DisplayTemporarily(Drawable toDisplay)
{ {
toDisplay.Animate( // avoid starting a new fade-in if one is already active.
b => b.FadeIn(500, Easing.OutQuint), if (fadeIn == null)
b => b.ResizeHeightTo(height, 500, Easing.OutQuint) {
).Then( fadeIn = toDisplay.Animate(
b => b.FadeOutFromOne(1500, Easing.InQuint), b => b.FadeIn(500, Easing.OutQuint),
b => b.ResizeHeightTo(height_contracted, 1500, Easing.InQuint) b => b.ResizeHeightTo(height, 500, Easing.OutQuint)
); );
fadeIn.Finally(_ => fadeIn = null);
}
fadeOut?.Cancel();
fadeOut = Scheduler.AddDelayed(() =>
{
toDisplay.Animate(
b => b.FadeOutFromOne(1500, Easing.InQuint),
b => b.ResizeHeightTo(height_contracted, 1500, Easing.InQuint));
}, 500);
} }
private class OptionLight : Container private class OptionLight : Container

View File

@ -158,6 +158,13 @@ namespace osu.Game.Overlays.Profile
} }
} }
}, },
new Box // this is a temporary workaround for incorrect masking behaviour of FillMode.Fill used in UserCoverBackground (see https://github.com/ppy/osu-framework/issues/1675)
{
RelativeSizeAxes = Axes.X,
Height = 1,
Y = cover_height,
Colour = OsuColour.Gray(34),
},
infoTextLeft = new LinkFlowContainer(t => t.TextSize = 14) infoTextLeft = new LinkFlowContainer(t => t.TextSize = 14)
{ {
X = UserProfileOverlay.CONTENT_X_MARGIN, X = UserProfileOverlay.CONTENT_X_MARGIN,
@ -360,11 +367,6 @@ namespace osu.Game.Overlays.Profile
Text = text Text = text
}; };
if (user.Age != null)
{
infoTextLeft.AddText($"{user.Age} years old ", boldItalic);
}
if (user.Country != null) if (user.Country != null)
{ {
infoTextLeft.AddText("From ", lightText); infoTextLeft.AddText("From ", lightText);

View File

@ -9,6 +9,7 @@ using osu.Framework.Localisation;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
namespace osu.Game.Overlays.Profile.Sections namespace osu.Game.Overlays.Profile.Sections
{ {
/// <summary> /// <summary>
@ -32,7 +33,10 @@ namespace osu.Game.Overlays.Profile.Sections
{ {
Action = () => Action = () =>
{ {
if (beatmap.BeatmapSet?.OnlineBeatmapSetID != null) beatmapSetOverlay?.FetchAndShowBeatmapSet(beatmap.BeatmapSet.OnlineBeatmapSetID.Value); if (beatmap.OnlineBeatmapID != null)
beatmapSetOverlay?.FetchAndShowBeatmap(beatmap.OnlineBeatmapID.Value);
else if (beatmap.BeatmapSet?.OnlineBeatmapSetID != null)
beatmapSetOverlay?.FetchAndShowBeatmapSet(beatmap.BeatmapSet.OnlineBeatmapSetID.Value);
}; };
Child = new FillFlowContainer Child = new FillFlowContainer

View File

@ -3,6 +3,7 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Configuration;
namespace osu.Game.Overlays.Settings namespace osu.Game.Overlays.Settings
{ {
@ -14,6 +15,8 @@ namespace osu.Game.Overlays.Settings
{ {
private readonly Ruleset ruleset; private readonly Ruleset ruleset;
protected IRulesetConfigManager Config;
protected RulesetSettingsSubsection(Ruleset ruleset) protected RulesetSettingsSubsection(Ruleset ruleset)
{ {
this.ruleset = ruleset; this.ruleset = ruleset;
@ -21,13 +24,13 @@ namespace osu.Game.Overlays.Settings
private DependencyContainer dependencies; private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{ {
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
var config = dependencies.Get<RulesetConfigCache>().GetConfigFor(ruleset); Config = dependencies.Get<RulesetConfigCache>().GetConfigFor(ruleset);
if (config != null) if (Config != null)
dependencies.Cache(config); dependencies.Cache(Config);
return dependencies; return dependencies;
} }

View File

@ -50,7 +50,7 @@ namespace osu.Game.Overlays.Toolbar
{ {
Action = () => OnHome?.Invoke() Action = () => OnHome?.Invoke()
}, },
new ToolbarModeSelector() new ToolbarRulesetSelector()
} }
}, },
new FillFlowContainer new FillFlowContainer

View File

@ -7,7 +7,7 @@ using OpenTK.Graphics;
namespace osu.Game.Overlays.Toolbar namespace osu.Game.Overlays.Toolbar
{ {
public class ToolbarModeButton : ToolbarButton public class ToolbarRulesetButton : ToolbarButton
{ {
private RulesetInfo ruleset; private RulesetInfo ruleset;
public RulesetInfo Ruleset public RulesetInfo Ruleset

View File

@ -16,18 +16,18 @@ using osu.Game.Rulesets;
namespace osu.Game.Overlays.Toolbar namespace osu.Game.Overlays.Toolbar
{ {
public class ToolbarModeSelector : Container public class ToolbarRulesetSelector : Container
{ {
private const float padding = 10; private const float padding = 10;
private readonly FillFlowContainer modeButtons; private readonly FillFlowContainer modeButtons;
private readonly Drawable modeButtonLine; private readonly Drawable modeButtonLine;
private ToolbarModeButton activeButton; private ToolbarRulesetButton activeButton;
private RulesetStore rulesets; private RulesetStore rulesets;
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>(); private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
public ToolbarModeSelector() public ToolbarRulesetSelector()
{ {
RelativeSizeAxes = Axes.Y; RelativeSizeAxes = Axes.Y;
@ -73,7 +73,7 @@ namespace osu.Game.Overlays.Toolbar
this.rulesets = rulesets; this.rulesets = rulesets;
foreach (var r in rulesets.AvailableRulesets) foreach (var r in rulesets.AvailableRulesets)
{ {
modeButtons.Add(new ToolbarModeButton modeButtons.Add(new ToolbarRulesetButton
{ {
Ruleset = r, Ruleset = r,
Action = delegate { ruleset.Value = r; } Action = delegate { ruleset.Value = r; }
@ -115,7 +115,7 @@ namespace osu.Game.Overlays.Toolbar
private void rulesetChanged(RulesetInfo ruleset) private void rulesetChanged(RulesetInfo ruleset)
{ {
foreach (ToolbarModeButton m in modeButtons.Children.Cast<ToolbarModeButton>()) foreach (ToolbarRulesetButton m in modeButtons.Children.Cast<ToolbarRulesetButton>())
{ {
bool isActive = m.Ruleset.ID == ruleset.ID; bool isActive = m.Ruleset.ID == ruleset.ID;
m.Active = isActive; m.Active = isActive;

View File

@ -70,7 +70,8 @@ namespace osu.Game.Rulesets.UI
protected readonly Ruleset Ruleset; protected readonly Ruleset Ruleset;
private IRulesetConfigManager rulesetConfig; protected IRulesetConfigManager Config { get; private set; }
private OnScreenDisplay onScreenDisplay; private OnScreenDisplay onScreenDisplay;
/// <summary> /// <summary>
@ -85,17 +86,17 @@ namespace osu.Game.Rulesets.UI
Cursor = CreateCursor(); Cursor = CreateCursor();
} }
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{ {
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
onScreenDisplay = dependencies.Get<OnScreenDisplay>(); onScreenDisplay = dependencies.Get<OnScreenDisplay>();
rulesetConfig = dependencies.Get<RulesetConfigCache>().GetConfigFor(Ruleset); Config = dependencies.Get<RulesetConfigCache>().GetConfigFor(Ruleset);
if (rulesetConfig != null) if (Config != null)
{ {
dependencies.Cache(rulesetConfig); dependencies.Cache(Config);
onScreenDisplay?.BeginTracking(this, rulesetConfig); onScreenDisplay?.BeginTracking(this, Config);
} }
return dependencies; return dependencies;
@ -143,10 +144,10 @@ namespace osu.Game.Rulesets.UI
{ {
base.Dispose(isDisposing); base.Dispose(isDisposing);
if (rulesetConfig != null) if (Config != null)
{ {
onScreenDisplay?.StopTracking(this, rulesetConfig); onScreenDisplay?.StopTracking(this, Config);
rulesetConfig = null; Config = null;
} }
} }
} }

View File

@ -222,23 +222,16 @@ namespace osu.Game.Rulesets.UI
mouseDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableButtons); mouseDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableButtons);
} }
protected override void TransformState(InputState state) protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{ {
base.TransformState(state); if (mouseDisabled.Value && (args.Button == MouseButton.Left || args.Button == MouseButton.Right)) return false;
return base.OnMouseDown(state, args);
}
// we don't want to transform the state if a replay is present (for now, at least). protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
if (replayInputHandler != null) return; {
if (!CurrentState.Mouse.IsPressed(args.Button)) return false;
var mouse = state.Mouse as Framework.Input.MouseState; return base.OnMouseUp(state, args);
if (mouse != null)
{
if (mouseDisabled.Value)
{
mouse.SetPressed(MouseButton.Left, false);
mouse.SetPressed(MouseButton.Right, false);
}
}
} }
#endregion #endregion

View File

@ -42,8 +42,8 @@ namespace osu.Game.Screens.Edit
private DependencyContainer dependencies; private DependencyContainer dependencies;
private GameHost host; private GameHost host;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); => dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours, GameHost host) private void load(OsuColour colours, GameHost host)

View File

@ -35,6 +35,12 @@ namespace osu.Game.Screens.Menu
private readonly Box boxHoverLayer; private readonly Box boxHoverLayer;
private readonly SpriteIcon icon; private readonly SpriteIcon icon;
private readonly string sampleName; private readonly string sampleName;
/// <summary>
/// The menu state for which we are visible for.
/// </summary>
public ButtonSystemState VisibleState = ButtonSystemState.TopLevel;
private readonly Action clickAction; private readonly Action clickAction;
private readonly Key triggerKey; private readonly Key triggerKey;
private SampleChannel sampleClick; private SampleChannel sampleClick;
@ -51,7 +57,7 @@ namespace osu.Game.Screens.Menu
AutoSizeAxes = Axes.Both; AutoSizeAxes = Axes.Both;
Alpha = 0; Alpha = 0;
Vector2 boxSize = new Vector2(ButtonSystem.BUTTON_WIDTH + Math.Abs(extraWidth), ButtonSystem.BUTTON_AREA_HEIGHT); Vector2 boxSize = new Vector2(ButtonSystem.BUTTON_WIDTH + Math.Abs(extraWidth), ButtonArea.BUTTON_AREA_HEIGHT);
Children = new Drawable[] Children = new Drawable[]
{ {
@ -260,6 +266,7 @@ namespace osu.Game.Screens.Menu
this.FadeOut(800); this.FadeOut(800);
break; break;
} }
break; break;
case ButtonState.Expanded: case ButtonState.Expanded:
const int expand_duration = 500; const int expand_duration = 500;
@ -276,6 +283,33 @@ namespace osu.Game.Screens.Menu
StateChanged?.Invoke(State); StateChanged?.Invoke(State);
} }
} }
public ButtonSystemState ButtonSystemState
{
set
{
ContractStyle = 0;
switch (value)
{
case ButtonSystemState.Initial:
State = ButtonState.Contracted;
break;
case ButtonSystemState.EnteringMode:
ContractStyle = 1;
State = ButtonState.Contracted;
break;
default:
if (value == VisibleState)
State = ButtonState.Expanded;
else if (value < VisibleState)
State = ButtonState.Contracted;
else
State = ButtonState.Exploded;
break;
}
}
}
} }
public enum ButtonState public enum ButtonState

View File

@ -0,0 +1,148 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using OpenTK;
namespace osu.Game.Screens.Menu
{
public class ButtonArea : Container, IStateful<Visibility>
{
public FlowContainerWithOrigin Flow;
protected override Container<Drawable> Content => Flow;
private readonly ButtonAreaBackground buttonAreaBackground;
private Visibility state;
public const float BUTTON_AREA_HEIGHT = 100;
public ButtonArea()
{
RelativeSizeAxes = Axes.Both;
InternalChild = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.X,
Size = new Vector2(1, BUTTON_AREA_HEIGHT),
Alpha = 0,
Children = new Drawable[]
{
buttonAreaBackground = new ButtonAreaBackground(),
Flow = new FlowContainerWithOrigin
{
Direction = FillDirection.Horizontal,
Spacing = new Vector2(-ButtonSystem.WEDGE_WIDTH, 0),
Anchor = Anchor.Centre,
AutoSizeAxes = Axes.Both,
}
}
};
}
public ButtonSystemState ButtonSystemState
{
set
{
switch (value)
{
case ButtonSystemState.Exit:
case ButtonSystemState.Initial:
case ButtonSystemState.EnteringMode:
State = Visibility.Hidden;
break;
case ButtonSystemState.TopLevel:
case ButtonSystemState.Play:
State = Visibility.Visible;
break;
}
buttonAreaBackground.ButtonSystemState = value;
}
}
public Visibility State
{
get => state;
set
{
if (value == state) return;
state = value;
InternalChild.FadeTo(state == Visibility.Hidden ? 0 : 1, 300);
StateChanged?.Invoke(state);
}
}
public event Action<Visibility> StateChanged;
private class ButtonAreaBackground : Box, IStateful<ButtonAreaBackgroundState>
{
private ButtonAreaBackgroundState state;
public ButtonAreaBackground()
{
RelativeSizeAxes = Axes.Both;
Size = new Vector2(2, 1);
Colour = OsuColour.Gray(50);
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
}
public ButtonAreaBackgroundState State
{
get => state;
set
{
if (value == state) return;
state = value;
switch (state)
{
case ButtonAreaBackgroundState.Flat:
this.ScaleTo(new Vector2(2, 0), 300, Easing.InSine);
break;
case ButtonAreaBackgroundState.Normal:
this.ScaleTo(Vector2.One, 400, Easing.OutQuint);
break;
}
StateChanged?.Invoke(state);
}
}
public ButtonSystemState ButtonSystemState
{
set
{
switch (value)
{
default:
State = ButtonAreaBackgroundState.Normal;
break;
case ButtonSystemState.Initial:
case ButtonSystemState.Exit:
case ButtonSystemState.EnteringMode:
State = ButtonAreaBackgroundState.Flat;
break;
}
}
}
public event Action<ButtonAreaBackgroundState> StateChanged;
}
public enum ButtonAreaBackgroundState
{
Normal,
Flat
}
}
}

View File

@ -10,8 +10,8 @@ using osu.Framework.Audio;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Framework.Logging;
using osu.Framework.Threading; using osu.Framework.Threading;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Input.Bindings; using osu.Game.Input.Bindings;
@ -22,9 +22,9 @@ using OpenTK.Input;
namespace osu.Game.Screens.Menu namespace osu.Game.Screens.Menu
{ {
public class ButtonSystem : Container, IStateful<MenuState>, IKeyBindingHandler<GlobalAction> public class ButtonSystem : Container, IStateful<ButtonSystemState>, IKeyBindingHandler<GlobalAction>
{ {
public event Action<MenuState> StateChanged; public event Action<ButtonSystemState> StateChanged;
public Action OnEdit; public Action OnEdit;
public Action OnExit; public Action OnExit;
@ -33,12 +33,6 @@ namespace osu.Game.Screens.Menu
public Action OnSettings; public Action OnSettings;
public Action OnMulti; public Action OnMulti;
public Action OnChart; public Action OnChart;
public Action OnTest;
private readonly FlowContainerWithOrigin buttonFlow;
//todo: make these non-internal somehow.
public const float BUTTON_AREA_HEIGHT = 100;
public const float BUTTON_WIDTH = 140f; public const float BUTTON_WIDTH = 140f;
public const float WEDGE_WIDTH = 20; public const float WEDGE_WIDTH = 20;
@ -54,18 +48,16 @@ namespace osu.Game.Screens.Menu
this.logo.Action = onOsuLogo; this.logo.Action = onOsuLogo;
// osuLogo.SizeForFlow relies on loading to be complete. // osuLogo.SizeForFlow relies on loading to be complete.
buttonFlow.Position = new Vector2(WEDGE_WIDTH * 2 - (BUTTON_WIDTH + this.logo.SizeForFlow / 4), 0); buttonArea.Flow.Position = new Vector2(WEDGE_WIDTH * 2 - (BUTTON_WIDTH + this.logo.SizeForFlow / 4), 0);
updateLogoState(); updateLogoState();
} }
} }
private readonly Drawable iconFacade; private readonly Drawable iconFacade;
private readonly Container buttonArea; private readonly ButtonArea buttonArea;
private readonly Box buttonAreaBackground;
private readonly Button backButton; private readonly Button backButton;
private readonly Button settingsButton;
private readonly List<Button> buttonsTopLevel = new List<Button>(); private readonly List<Button> buttonsTopLevel = new List<Button>();
private readonly List<Button> buttonsPlay = new List<Button>(); private readonly List<Button> buttonsPlay = new List<Button>();
@ -76,57 +68,35 @@ namespace osu.Game.Screens.Menu
{ {
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
Children = new Drawable[] Child = buttonArea = new ButtonArea();
buttonArea.AddRange(new[]
{ {
buttonArea = new Container new Button(@"settings", string.Empty, FontAwesome.fa_gear, new Color4(85, 85, 85, 255), () => OnSettings?.Invoke(), -WEDGE_WIDTH, Key.O),
backButton = new Button(@"back", @"button-back-select", FontAwesome.fa_osu_left_o, new Color4(51, 58, 94, 255), () => State = ButtonSystemState.TopLevel, -WEDGE_WIDTH)
{ {
Anchor = Anchor.Centre, VisibleState = ButtonSystemState.Play,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.X,
Size = new Vector2(1, BUTTON_AREA_HEIGHT),
Alpha = 0,
Children = new Drawable[]
{
buttonAreaBackground = new Box
{
RelativeSizeAxes = Axes.Both,
Size = new Vector2(2, 1),
Colour = OsuColour.Gray(50),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
buttonFlow = new FlowContainerWithOrigin
{
Direction = FillDirection.Horizontal,
Spacing = new Vector2(-WEDGE_WIDTH, 0),
Anchor = Anchor.Centre,
AutoSizeAxes = Axes.Both,
Children = new[]
{
settingsButton = new Button(@"settings", string.Empty, FontAwesome.fa_gear, new Color4(85, 85, 85, 255), () => OnSettings?.Invoke(), -WEDGE_WIDTH, Key.O),
backButton = new Button(@"back", string.Empty, FontAwesome.fa_osu_left_o, new Color4(51, 58, 94, 255), onBack, -WEDGE_WIDTH),
iconFacade = new Container //need a container to make the osu! icon flow properly.
{
Size = new Vector2(0, BUTTON_AREA_HEIGHT)
}
},
CentreTarget = iconFacade
}
}
}, },
}; iconFacade = new Container //need a container to make the osu! icon flow properly.
{
Size = new Vector2(0, ButtonArea.BUTTON_AREA_HEIGHT)
}
});
buttonArea.Flow.CentreTarget = iconFacade;
buttonsPlay.Add(new Button(@"solo", @"button-solo-select", FontAwesome.fa_user, new Color4(102, 68, 204, 255), () => OnSolo?.Invoke(), WEDGE_WIDTH, Key.P)); buttonsPlay.Add(new Button(@"solo", @"button-solo-select", FontAwesome.fa_user, new Color4(102, 68, 204, 255), () => OnSolo?.Invoke(), WEDGE_WIDTH, Key.P));
buttonsPlay.Add(new Button(@"multi", @"button-generic-select", FontAwesome.fa_users, new Color4(94, 63, 186, 255), () => OnMulti?.Invoke(), 0, Key.M)); buttonsPlay.Add(new Button(@"multi", @"button-generic-select", FontAwesome.fa_users, new Color4(94, 63, 186, 255), () => OnMulti?.Invoke(), 0, Key.M));
buttonsPlay.Add(new Button(@"chart", @"button-generic-select", FontAwesome.fa_osu_charts, new Color4(80, 53, 160, 255), () => OnChart?.Invoke())); buttonsPlay.Add(new Button(@"chart", @"button-generic-select", FontAwesome.fa_osu_charts, new Color4(80, 53, 160, 255), () => OnChart?.Invoke()));
buttonsPlay.ForEach(b => b.VisibleState = ButtonSystemState.Play);
buttonsTopLevel.Add(new Button(@"play", @"button-play-select", FontAwesome.fa_osu_logo, new Color4(102, 68, 204, 255), onPlay, WEDGE_WIDTH, Key.P)); buttonsTopLevel.Add(new Button(@"play", @"button-play-select", FontAwesome.fa_osu_logo, new Color4(102, 68, 204, 255), () => State = ButtonSystemState.Play, WEDGE_WIDTH, Key.P));
buttonsTopLevel.Add(new Button(@"osu!editor", @"button-generic-select", FontAwesome.fa_osu_edit_o, new Color4(238, 170, 0, 255), () => OnEdit?.Invoke(), 0, Key.E)); buttonsTopLevel.Add(new Button(@"osu!editor", @"button-generic-select", FontAwesome.fa_osu_edit_o, new Color4(238, 170, 0, 255), () => OnEdit?.Invoke(), 0, Key.E));
buttonsTopLevel.Add(new Button(@"osu!direct", @"button-direct-select", FontAwesome.fa_osu_chevron_down_o, new Color4(165, 204, 0, 255), () => OnDirect?.Invoke(), 0, Key.D)); buttonsTopLevel.Add(new Button(@"osu!direct", @"button-direct-select", FontAwesome.fa_osu_chevron_down_o, new Color4(165, 204, 0, 255), () => OnDirect?.Invoke(), 0, Key.D));
buttonsTopLevel.Add(new Button(@"exit", string.Empty, FontAwesome.fa_osu_cross_o, new Color4(238, 51, 153, 255), onExit, 0, Key.Q)); buttonsTopLevel.Add(new Button(@"exit", string.Empty, FontAwesome.fa_osu_cross_o, new Color4(238, 51, 153, 255), () => OnExit?.Invoke(), 0, Key.Q));
buttonFlow.AddRange(buttonsPlay); buttonArea.AddRange(buttonsPlay);
buttonFlow.AddRange(buttonsTopLevel); buttonArea.AddRange(buttonsTopLevel);
} }
private OsuGame game; private OsuGame game;
@ -152,14 +122,17 @@ namespace osu.Game.Screens.Menu
} }
} }
public bool OnReleased(GlobalAction action) => false;
private bool goBack() private bool goBack()
{ {
switch (State) switch (State)
{ {
case MenuState.TopLevel: case ButtonSystemState.TopLevel:
State = MenuState.Initial; State = ButtonSystemState.Initial;
sampleBack?.Play();
return true; return true;
case MenuState.Play: case ButtonSystemState.Play:
backButton.TriggerOnClick(); backButton.TriggerOnClick();
return true; return true;
default: default:
@ -167,48 +140,30 @@ namespace osu.Game.Screens.Menu
} }
} }
public bool OnReleased(GlobalAction action) => false;
private void onPlay()
{
State = MenuState.Play;
}
private void onExit()
{
OnExit?.Invoke();
}
private void onBack()
{
sampleBack?.Play();
State = MenuState.TopLevel;
}
private bool onOsuLogo() private bool onOsuLogo()
{ {
switch (state) switch (state)
{ {
default: default:
return true; return true;
case MenuState.Initial: case ButtonSystemState.Initial:
State = MenuState.TopLevel; State = ButtonSystemState.TopLevel;
return true; return true;
case MenuState.TopLevel: case ButtonSystemState.TopLevel:
buttonsTopLevel.First().TriggerOnClick(); buttonsTopLevel.First().TriggerOnClick();
return false; return false;
case MenuState.Play: case ButtonSystemState.Play:
buttonsPlay.First().TriggerOnClick(); buttonsPlay.First().TriggerOnClick();
return false; return false;
} }
} }
private MenuState state; private ButtonSystemState state = ButtonSystemState.Initial;
public override bool HandleKeyboardInput => state != MenuState.Exit; public override bool HandleKeyboardInput => state != ButtonSystemState.Exit;
public override bool HandleMouseInput => state != MenuState.Exit; public override bool HandleMouseInput => state != ButtonSystemState.Exit;
public MenuState State public ButtonSystemState State
{ {
get { return state; } get { return state; }
@ -216,71 +171,19 @@ namespace osu.Game.Screens.Menu
{ {
if (state == value) return; if (state == value) return;
MenuState lastState = state; ButtonSystemState lastState = state;
state = value; state = value;
//todo: figure a more elegant way of doing this.
buttonsTopLevel.ForEach(b => b.ContractStyle = 0);
buttonsPlay.ForEach(b => b.ContractStyle = 0);
backButton.ContractStyle = 0;
settingsButton.ContractStyle = 0;
updateLogoState(lastState); updateLogoState(lastState);
using (buttonArea.BeginDelayedSequence(lastState == MenuState.Initial ? 150 : 0, true)) Logger.Log($"{nameof(ButtonSystem)}'s state changed from {lastState} to {state}");
using (buttonArea.BeginDelayedSequence(lastState == ButtonSystemState.Initial ? 150 : 0, true))
{ {
switch (state) buttonArea.ButtonSystemState = state;
{
case MenuState.Exit:
case MenuState.Initial:
buttonAreaBackground.ScaleTo(Vector2.One, 500, Easing.Out);
buttonArea.FadeOut(300);
foreach (Button b in buttonsTopLevel) foreach (var b in buttonArea.Children.OfType<Button>())
b.State = ButtonState.Contracted; b.ButtonSystemState = state;
foreach (Button b in buttonsPlay)
b.State = ButtonState.Contracted;
if (state != MenuState.Exit && lastState == MenuState.TopLevel)
sampleBack?.Play();
break;
case MenuState.TopLevel:
buttonAreaBackground.ScaleTo(Vector2.One, 200, Easing.Out);
buttonArea.FadeIn(300);
foreach (Button b in buttonsTopLevel)
b.State = ButtonState.Expanded;
foreach (Button b in buttonsPlay)
b.State = ButtonState.Contracted;
break;
case MenuState.Play:
foreach (Button b in buttonsTopLevel)
b.State = ButtonState.Exploded;
foreach (Button b in buttonsPlay)
b.State = ButtonState.Expanded;
break;
case MenuState.EnteringMode:
buttonAreaBackground.ScaleTo(new Vector2(2, 0), 300, Easing.InSine);
buttonsTopLevel.ForEach(b => b.ContractStyle = 1);
buttonsPlay.ForEach(b => b.ContractStyle = 1);
backButton.ContractStyle = 1;
settingsButton.ContractStyle = 1;
foreach (Button b in buttonsTopLevel)
b.State = ButtonState.Contracted;
foreach (Button b in buttonsPlay)
b.State = ButtonState.Contracted;
break;
}
backButton.State = state == MenuState.Play ? ButtonState.Expanded : ButtonState.Contracted;
settingsButton.State = state == MenuState.TopLevel ? ButtonState.Expanded : ButtonState.Contracted;
} }
StateChanged?.Invoke(State); StateChanged?.Invoke(State);
@ -289,14 +192,14 @@ namespace osu.Game.Screens.Menu
private ScheduledDelegate logoDelayedAction; private ScheduledDelegate logoDelayedAction;
private void updateLogoState(MenuState lastState = MenuState.Initial) private void updateLogoState(ButtonSystemState lastState = ButtonSystemState.Initial)
{ {
if (logo == null) return; if (logo == null) return;
switch (state) switch (state)
{ {
case MenuState.Exit: case ButtonSystemState.Exit:
case MenuState.Initial: case ButtonSystemState.Initial:
logoDelayedAction?.Cancel(); logoDelayedAction?.Cancel();
logoDelayedAction = Scheduler.AddDelayed(() => logoDelayedAction = Scheduler.AddDelayed(() =>
{ {
@ -304,7 +207,7 @@ namespace osu.Game.Screens.Menu
if (game != null) if (game != null)
{ {
game.OverlayActivationMode.Value = state == MenuState.Exit ? OverlayActivation.Disabled : OverlayActivation.All; game.OverlayActivationMode.Value = state == ButtonSystemState.Exit ? OverlayActivation.Disabled : OverlayActivation.All;
game.Toolbar.Hide(); game.Toolbar.Hide();
} }
@ -315,22 +218,22 @@ namespace osu.Game.Screens.Menu
logo.ScaleTo(1, 800, Easing.OutExpo); logo.ScaleTo(1, 800, Easing.OutExpo);
}, buttonArea.Alpha * 150); }, buttonArea.Alpha * 150);
break; break;
case MenuState.TopLevel: case ButtonSystemState.TopLevel:
case MenuState.Play: case ButtonSystemState.Play:
switch (lastState) switch (lastState)
{ {
case MenuState.TopLevel: // coming from toplevel to play case ButtonSystemState.TopLevel: // coming from toplevel to play
break; break;
case MenuState.Initial: case ButtonSystemState.Initial:
logo.ClearTransforms(targetMember: nameof(Position)); logo.ClearTransforms(targetMember: nameof(Position));
logo.RelativePositionAxes = Axes.None; logo.RelativePositionAxes = Axes.None;
bool impact = logo.Scale.X > 0.6f; bool impact = logo.Scale.X > 0.6f;
if (lastState == MenuState.Initial) if (lastState == ButtonSystemState.Initial)
logo.ScaleTo(0.5f, 200, Easing.In); logo.ScaleTo(0.5f, 200, Easing.In);
logo.MoveTo(logoTrackingPosition, lastState == MenuState.EnteringMode ? 0 : 200, Easing.In); logo.MoveTo(logoTrackingPosition, lastState == ButtonSystemState.EnteringMode ? 0 : 200, Easing.In);
logoDelayedAction?.Cancel(); logoDelayedAction?.Cancel();
logoDelayedAction = Scheduler.AddDelayed(() => logoDelayedAction = Scheduler.AddDelayed(() =>
@ -356,7 +259,7 @@ namespace osu.Game.Screens.Menu
} }
break; break;
case MenuState.EnteringMode: case ButtonSystemState.EnteringMode:
logoTracking = true; logoTracking = true;
break; break;
} }
@ -375,7 +278,7 @@ namespace osu.Game.Screens.Menu
if (logo != null) if (logo != null)
{ {
if (logoTracking) if (logoTracking && iconFacade.IsLoaded)
logo.Position = logoTrackingPosition; logo.Position = logoTrackingPosition;
iconFacade.Width = logo.SizeForFlow * 0.5f; iconFacade.Width = logo.SizeForFlow * 0.5f;
@ -383,12 +286,12 @@ namespace osu.Game.Screens.Menu
} }
} }
public enum MenuState public enum ButtonSystemState
{ {
Exit,
Initial, Initial,
TopLevel, TopLevel,
Play, Play,
EnteringMode, EnteringMode,
Exit,
} }
} }

View File

@ -3,10 +3,9 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Containers;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Game.Overlays; using osu.Game.Overlays;
@ -16,96 +15,89 @@ namespace osu.Game.Screens.Menu
public class Disclaimer : OsuScreen public class Disclaimer : OsuScreen
{ {
private Intro intro; private Intro intro;
private readonly SpriteIcon icon; private SpriteIcon icon;
private Color4 iconColour; private Color4 iconColour;
private LinkFlowContainer textFlow;
protected override bool HideOverlaysOnEnter => true; protected override bool HideOverlaysOnEnter => true;
protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled; protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled;
public override bool CursorVisible => false; public override bool CursorVisible => false;
private const float icon_y = -0.09f;
public Disclaimer() public Disclaimer()
{ {
ValidForResume = false; ValidForResume = false;
Children = new Drawable[]
{
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 2),
Children = new Drawable[]
{
icon = new SpriteIcon
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Icon = FontAwesome.fa_warning,
Size = new Vector2(30),
},
new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
TextSize = 30,
Text = "This is a development build",
Margin = new MarginPadding
{
Bottom = 20
},
},
new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = "Don't expect shit to work perfectly as this is very much a work in progress."
},
new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = "Don't report bugs because we are aware. Don't complain about missing features because we are adding them."
},
new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = "Sit back and enjoy. Visit discord.gg/ppy if you want to help out!",
Margin = new MarginPadding { Bottom = 20 },
},
new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
TextSize = 12,
Text = "oh and yes, you will get seizures.",
},
}
}
};
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
LoadComponentAsync(intro = new Intro()); Children = new Drawable[]
{
icon = new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Icon = FontAwesome.fa_warning,
Size = new Vector2(30),
RelativePositionAxes = Axes.Both,
Y = icon_y,
},
textFlow = new LinkFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding(50),
TextAnchor = Anchor.TopCentre,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Spacing = new Vector2(0, 2),
}
};
textFlow.AddText("This is an ", t =>
{
t.TextSize = 30;
t.Font = @"Exo2.0-Light";
});
textFlow.AddText("early development build", t =>
{
t.TextSize = 30;
t.Font = @"Exo2.0-SemiBold";
});
textFlow.AddParagraph("Don't expect everything to work perfectly.");
textFlow.AddParagraph("");
textFlow.AddParagraph("Detailed bug reports are welcomed via github issues.");
textFlow.AddParagraph("");
textFlow.AddText("Visit ");
textFlow.AddLink("discord.gg/ppy", "https://discord.gg/ppy");
textFlow.AddText(" if you want to help out or follow progress!");
iconColour = colours.Yellow; iconColour = colours.Yellow;
} }
protected override void LoadComplete()
{
base.LoadComplete();
LoadComponentAsync(intro = new Intro());
}
protected override void OnEntering(Screen last) protected override void OnEntering(Screen last)
{ {
base.OnEntering(last); base.OnEntering(last);
icon.Delay(1500).FadeColour(iconColour, 200); icon.Delay(1500).FadeColour(iconColour, 200, Easing.OutQuint);
icon.Delay(1500).MoveToY(icon_y * 1.1f, 100, Easing.OutCirc).Then().MoveToY(icon_y, 100, Easing.InCirc);
Content Content
.FadeInFromZero(500) .FadeInFromZero(500)
.Then(5500) .Then(5500)
.FadeOut(250) .FadeOut(250)
.ScaleTo(0.9f, 250, Easing.InQuint)
.Finally(d => Push(intro)); .Finally(d => Push(intro));
} }
} }

View File

@ -24,9 +24,9 @@ namespace osu.Game.Screens.Menu
{ {
private readonly ButtonSystem buttons; private readonly ButtonSystem buttons;
protected override bool HideOverlaysOnEnter => buttons.State == MenuState.Initial; protected override bool HideOverlaysOnEnter => buttons.State == ButtonSystemState.Initial;
protected override bool AllowBackButton => buttons.State != MenuState.Initial; protected override bool AllowBackButton => buttons.State != ButtonSystemState.Initial;
private readonly BackgroundScreenDefault background; private readonly BackgroundScreenDefault background;
private Screen songSelect; private Screen songSelect;
@ -123,7 +123,7 @@ namespace osu.Game.Screens.Menu
if (resuming) if (resuming)
{ {
buttons.State = MenuState.TopLevel; buttons.State = ButtonSystemState.TopLevel;
const float length = 300; const float length = 300;
@ -155,7 +155,7 @@ namespace osu.Game.Screens.Menu
const float length = 400; const float length = 400;
buttons.State = MenuState.EnteringMode; buttons.State = ButtonSystemState.EnteringMode;
Content.FadeOut(length, Easing.InSine); Content.FadeOut(length, Easing.InSine);
Content.MoveTo(new Vector2(-800, 0), length, Easing.InSine); Content.MoveTo(new Vector2(-800, 0), length, Easing.InSine);
@ -175,7 +175,7 @@ namespace osu.Game.Screens.Menu
protected override bool OnExiting(Screen next) protected override bool OnExiting(Screen next)
{ {
buttons.State = MenuState.Exit; buttons.State = ButtonSystemState.Exit;
Content.FadeOut(3000); Content.FadeOut(3000);
return base.OnExiting(next); return base.OnExiting(next);
} }

View File

@ -19,6 +19,7 @@ using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using OpenTK.Input;
namespace osu.Game.Screens.Menu namespace osu.Game.Screens.Menu
{ {
@ -345,12 +346,16 @@ namespace osu.Game.Screens.Menu
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{ {
if (args.Button != MouseButton.Left) return false;
logoBounceContainer.ScaleTo(0.9f, 1000, Easing.Out); logoBounceContainer.ScaleTo(0.9f, 1000, Easing.Out);
return true; return true;
} }
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{ {
if (args.Button != MouseButton.Left) return false;
logoBounceContainer.ScaleTo(1f, 500, Easing.OutElastic); logoBounceContainer.ScaleTo(1f, 500, Easing.OutElastic);
return true; return true;
} }

View File

@ -46,7 +46,9 @@ namespace osu.Game.Screens.Select.Leaderboards
public void UpdateRank(ScoreRank newRank) public void UpdateRank(ScoreRank newRank)
{ {
Rank = newRank; Rank = newRank;
updateTexture();
if (IsLoaded)
updateTexture();
} }
} }
} }

View File

@ -69,8 +69,8 @@ namespace osu.Game.Screens.Select
private DependencyContainer dependencies; private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); => dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
protected SongSelect() protected SongSelect()
{ {
@ -138,7 +138,11 @@ namespace osu.Game.Screens.Select
Height = filter_height, Height = filter_height,
FilterChanged = c => Carousel.Filter(c), FilterChanged = c => Carousel.Filter(c),
Background = { Width = 2 }, Background = { Width = 2 },
Exit = Exit, Exit = () =>
{
if (IsCurrentScreen)
Exit();
},
}, },
} }
}, },
@ -189,8 +193,6 @@ namespace osu.Game.Screens.Select
dependencies.CacheAs(Ruleset); dependencies.CacheAs(Ruleset);
dependencies.CacheAs<IBindable<RulesetInfo>>(Ruleset); dependencies.CacheAs<IBindable<RulesetInfo>>(Ruleset);
base.Ruleset.ValueChanged += r => updateSelectedBeatmap(beatmapNoDebounce);
if (Footer != null) if (Footer != null)
{ {
Footer.AddButton(@"random", colours.Green, triggerRandom, Key.F2); Footer.AddButton(@"random", colours.Green, triggerRandom, Key.F2);
@ -218,6 +220,12 @@ namespace osu.Game.Screens.Select
Beatmap.BindValueChanged(workingBeatmapChanged); Beatmap.BindValueChanged(workingBeatmapChanged);
} }
protected override void LoadComplete()
{
base.LoadComplete();
base.Ruleset.ValueChanged += r => updateSelectedBeatmap(beatmapNoDebounce);
}
public void Edit(BeatmapInfo beatmap) public void Edit(BeatmapInfo beatmap)
{ {
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, Beatmap.Value); Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, Beatmap.Value);
@ -231,6 +239,10 @@ namespace osu.Game.Screens.Select
/// <param name="performStartAction">Whether to trigger <see cref="OnStart"/>.</param> /// <param name="performStartAction">Whether to trigger <see cref="OnStart"/>.</param>
public void FinaliseSelection(BeatmapInfo beatmap = null, bool performStartAction = true) public void FinaliseSelection(BeatmapInfo beatmap = null, bool performStartAction = true)
{ {
// avoid attempting to continue before a selection has been obtained.
// this could happen via a user interaction while the carousel is still in a loading state.
if (Carousel.SelectedBeatmap == null) return;
// if we have a pending filter operation, we want to run it now. // if we have a pending filter operation, we want to run it now.
// it could change selection (ie. if the ruleset has been changed). // it could change selection (ie. if the ruleset has been changed).
Carousel.FlushPendingFilterOperations(); Carousel.FlushPendingFilterOperations();

View File

@ -49,8 +49,8 @@ namespace osu.Game.Screens.Tournament
private DependencyContainer dependencies; private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) =>
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(TextureStore textures, Storage storage) private void load(TextureStore textures, Storage storage)

View File

@ -71,9 +71,9 @@ namespace osu.Game.Skinning
private void onSourceChanged() => SourceChanged?.Invoke(); private void onSourceChanged() => SourceChanged?.Invoke();
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{ {
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
fallbackSource = dependencies.Get<ISkinSource>(); fallbackSource = dependencies.Get<ISkinSource>();
dependencies.CacheAs<ISkinSource>(this); dependencies.CacheAs<ISkinSource>(this);

View File

@ -36,8 +36,8 @@ namespace osu.Game.Storyboards.Drawables
public override bool RemoveCompletedTransforms => false; public override bool RemoveCompletedTransforms => false;
private DependencyContainer dependencies; private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) =>
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
public DrawableStoryboard(Storyboard storyboard) public DrawableStoryboard(Storyboard storyboard)
{ {

View File

@ -0,0 +1,69 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.IO;
using osu.Framework.Allocation;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
namespace osu.Game.Storyboards.Drawables
{
public class DrawableStoryboardSample : Component
{
/// <summary>
/// The amount of time allowable beyond the start time of the sample, for the sample to start.
/// </summary>
private const double allowable_late_start = 100;
private readonly StoryboardSample sample;
private SampleChannel channel;
public override bool RemoveWhenNotAlive => false;
public DrawableStoryboardSample(StoryboardSample sample)
{
this.sample = sample;
LifetimeStart = sample.Time;
}
[BackgroundDependencyLoader]
private void load(IBindableBeatmap 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));
if (channel != null)
channel.Volume.Value = sample.Volume / 100;
}
protected override void Update()
{
base.Update();
// TODO: this logic will need to be consolidated with other game samples like hitsounds.
if (Time.Current < sample.Time)
{
// 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.Time;
LifetimeEnd = double.MaxValue;
}
else if (Time.Current - Time.Elapsed < sample.Time)
{
// 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.Time < 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.Time;
}
}
}
}

View File

@ -2,14 +2,14 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics; using osu.Framework.Graphics;
using System; using osu.Game.Storyboards.Drawables;
namespace osu.Game.Storyboards namespace osu.Game.Storyboards
{ {
public class StoryboardSample : IStoryboardElement public class StoryboardSample : IStoryboardElement
{ {
public string Path { get; set; } public string Path { get; set; }
public bool IsDrawable => false; public bool IsDrawable => true;
public double Time; public double Time;
public float Volume; public float Volume;
@ -21,9 +21,6 @@ namespace osu.Game.Storyboards
Volume = volume; Volume = volume;
} }
public Drawable CreateDrawable() public Drawable CreateDrawable() => new DrawableStoryboardSample(this);
{
throw new InvalidOperationException();
}
} }
} }

View File

@ -25,9 +25,9 @@ namespace osu.Game.Tests.Visual
Clock = new EditorClock(new ControlPointInfo(), 5000, BeatDivisor) { IsCoupled = false }; Clock = new EditorClock(new ControlPointInfo(), 5000, BeatDivisor) { IsCoupled = false };
} }
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{ {
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.Cache(BeatDivisor); dependencies.Cache(BeatDivisor);
dependencies.CacheAs<IFrameBasedClock>(Clock); dependencies.CacheAs<IFrameBasedClock>(Clock);

View File

@ -20,9 +20,9 @@ namespace osu.Game.Tests.Visual
protected DependencyContainer Dependencies { get; private set; } protected DependencyContainer Dependencies { get; private set; }
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{ {
Dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); Dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
Dependencies.CacheAs<BindableBeatmap>(beatmap); Dependencies.CacheAs<BindableBeatmap>(beatmap);
Dependencies.CacheAs<IBindableBeatmap>(beatmap); Dependencies.CacheAs<IBindableBeatmap>(beatmap);

View File

@ -42,7 +42,9 @@ namespace osu.Game.Users
return; return;
country = value; country = value;
sprite.Texture = getFlagTexture();
if (IsLoaded)
sprite.Texture = getFlagTexture();
} }
} }

View File

@ -23,9 +23,6 @@ namespace osu.Game.Users
public Bindable<UserStatus> Status = new Bindable<UserStatus>(); public Bindable<UserStatus> Status = new Bindable<UserStatus>();
[JsonProperty(@"age")]
public int? Age;
//public Team Team; //public Team Team;
[JsonProperty(@"profile_colour")] [JsonProperty(@"profile_colour")]

View File

@ -14,11 +14,11 @@
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj" /> <ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Humanizer" Version="2.3.3" /> <PackageReference Include="Humanizer" Version="2.4.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.1" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="ppy.osu.Framework" Version="2018.705.0" /> <PackageReference Include="ppy.osu.Framework" Version="2018.712.0" />
<PackageReference Include="SharpCompress" Version="0.17.1" /> <PackageReference Include="SharpCompress" Version="0.17.1" />
<PackageReference Include="NUnit" Version="3.10.1" /> <PackageReference Include="NUnit" Version="3.10.1" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />

View File

@ -23,6 +23,7 @@
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ClassWithVirtualMembersNeverInherited_002EGlobal/@EntryIndexedValue">HINT</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ClassWithVirtualMembersNeverInherited_002EGlobal/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CollectionNeverQueried_002EGlobal/@EntryIndexedValue">SUGGESTION</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CollectionNeverQueried_002EGlobal/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CollectionNeverQueried_002ELocal/@EntryIndexedValue">HINT</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CollectionNeverQueried_002ELocal/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CommentTypo/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CompareOfFloatsByEqualityOperator/@EntryIndexedValue">HINT</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CompareOfFloatsByEqualityOperator/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertClosureToMethodGroup/@EntryIndexedValue">WARNING</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertClosureToMethodGroup/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertIfDoToWhile/@EntryIndexedValue">WARNING</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertIfDoToWhile/@EntryIndexedValue">WARNING</s:String>
@ -43,6 +44,7 @@
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=FieldCanBeMadeReadOnly_002EGlobal/@EntryIndexedValue">DO_NOT_SHOW</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=FieldCanBeMadeReadOnly_002EGlobal/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=FieldCanBeMadeReadOnly_002ELocal/@EntryIndexedValue">WARNING</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=FieldCanBeMadeReadOnly_002ELocal/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ForCanBeConvertedToForeach/@EntryIndexedValue">WARNING</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ForCanBeConvertedToForeach/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=IdentifierTypo/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ImpureMethodCallOnReadonlyValueField/@EntryIndexedValue">HINT</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ImpureMethodCallOnReadonlyValueField/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=InconsistentNaming/@EntryIndexedValue">ERROR</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=InconsistentNaming/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=InheritdocConsiderUsage/@EntryIndexedValue">HINT</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=InheritdocConsiderUsage/@EntryIndexedValue">HINT</s:String>
@ -133,6 +135,7 @@
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleOrDefault_002E2/@EntryIndexedValue">WARNING</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleOrDefault_002E2/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleOrDefault_002E3/@EntryIndexedValue">WARNING</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleOrDefault_002E3/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleOrDefault_002E4/@EntryIndexedValue">WARNING</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleOrDefault_002E4/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=StringLiteralTypo/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FBuiltInTypes/@EntryIndexedValue">DO_NOT_SHOW</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FBuiltInTypes/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FSimpleTypes/@EntryIndexedValue">DO_NOT_SHOW</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FSimpleTypes/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SwitchStatementMissingSomeCases/@EntryIndexedValue">DO_NOT_SHOW</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SwitchStatementMissingSomeCases/@EntryIndexedValue">DO_NOT_SHOW</s:String>
@ -666,4 +669,22 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAlwaysTreatStructAsNotReorderableMigration/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAlwaysTreatStructAsNotReorderableMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Beatmap/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=beatmaps/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=beatmap_0027s/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=bindable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Catmull/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Drawables/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=gameplay/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=hitobjects/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=keymods/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Kiai/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Leaderboard/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Leaderboards/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Playfield/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=resampler/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ruleset/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=rulesets/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Taiko/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Unranked/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>