mirror of
https://github.com/ppy/osu.git
synced 2026-05-14 03:02:37 +08:00
Compare commits
52 Commits
2018.906.0
...
2018.910.0
@@ -24,7 +24,9 @@ Clone the repository including submodules
|
||||
Build and run
|
||||
|
||||
- Using Visual Studio 2017, Rider or Visual Studio Code (configurations are included)
|
||||
- From command line using `dotnet run --project osu.Desktop`
|
||||
- From command line using `dotnet run --project osu.Desktop`. When building for non-development purposes, add `-c Release` to gain higher performance.
|
||||
|
||||
Note: If you run from command line under linux, you will need to prefix the output folder to your `LD_LIBRARY_PATH`. See `.vscode/launch.json` for an example
|
||||
|
||||
If you run into issues building you may need to restore nuget packages (commonly via `dotnet restore`). Visual Studio Code users must run `Restore` task from debug tab before attempt to build.
|
||||
|
||||
|
||||
@@ -111,6 +111,18 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
bodyPiece.Height = DrawHeight - Head.Height / 2 + Tail.Height / 2;
|
||||
}
|
||||
|
||||
protected void BeginHold()
|
||||
{
|
||||
holdStartTime = Time.Current;
|
||||
bodyPiece.Hitting = true;
|
||||
}
|
||||
|
||||
protected void EndHold()
|
||||
{
|
||||
holdStartTime = null;
|
||||
bodyPiece.Hitting = false;
|
||||
}
|
||||
|
||||
public bool OnPressed(ManiaAction action)
|
||||
{
|
||||
// Make sure the action happened within the body of the hold note
|
||||
@@ -123,8 +135,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
// The user has pressed during the body of the hold note, after the head note and its hit windows have passed
|
||||
// and within the limited range of the above if-statement. This state will be managed by the head note if the
|
||||
// user has pressed during the hit windows of the head note.
|
||||
holdStartTime = Time.Current;
|
||||
|
||||
BeginHold();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -137,7 +148,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
if (action != Action.Value)
|
||||
return false;
|
||||
|
||||
holdStartTime = null;
|
||||
EndHold();
|
||||
|
||||
// If the key has been released too early, the user should not receive full score for the release
|
||||
if (!Tail.IsHit)
|
||||
@@ -170,7 +181,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
|
||||
// The head note also handles early hits before the body, but we want accurate early hits to count as the body being held
|
||||
// The body doesn't handle these early early hits, so we have to explicitly set the holding state here
|
||||
holdNote.holdStartTime = Time.Current;
|
||||
holdNote.BeginHold();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
||||
background = new Box { RelativeSizeAxes = Axes.Both },
|
||||
foreground = new BufferedContainer
|
||||
{
|
||||
Blending = BlendingMode.Additive,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
CacheDrawnFrameBuffer = true,
|
||||
Children = new Drawable[]
|
||||
@@ -73,6 +74,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
||||
}
|
||||
|
||||
private Color4 accentColour;
|
||||
|
||||
public Color4 AccentColour
|
||||
{
|
||||
get { return accentColour; }
|
||||
@@ -86,6 +88,16 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
||||
}
|
||||
}
|
||||
|
||||
public bool Hitting
|
||||
{
|
||||
get { return hitting; }
|
||||
set
|
||||
{
|
||||
hitting = value;
|
||||
updateAccentColour();
|
||||
}
|
||||
}
|
||||
|
||||
private Cached subtractionCache = new Cached();
|
||||
|
||||
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
|
||||
@@ -118,13 +130,26 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
||||
}
|
||||
}
|
||||
|
||||
private bool hitting;
|
||||
|
||||
private void updateAccentColour()
|
||||
{
|
||||
if (!IsLoaded)
|
||||
return;
|
||||
|
||||
foreground.Colour = AccentColour.Opacity(0.9f);
|
||||
background.Colour = AccentColour.Opacity(0.6f);
|
||||
foreground.Colour = AccentColour.Opacity(0.5f);
|
||||
background.Colour = AccentColour.Opacity(0.7f);
|
||||
|
||||
const float animation_length = 50;
|
||||
|
||||
foreground.ClearTransforms(false, nameof(foreground.Colour));
|
||||
if (hitting)
|
||||
{
|
||||
// wait for the next sync point
|
||||
double synchronisedOffset = animation_length * 2 - Time.Current % (animation_length * 2);
|
||||
using (foreground.BeginDelayedSequence(synchronisedOffset))
|
||||
foreground.FadeColour(AccentColour.Lighten(0.2f), animation_length).Then().FadeColour(foreground.Colour, animation_length).Loop();
|
||||
}
|
||||
|
||||
subtractionCache.Invalidate();
|
||||
}
|
||||
|
||||
@@ -7,14 +7,15 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Lines;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics.ES30;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using OpenTK;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
@@ -43,6 +44,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
public double? SnakedEnd { get; private set; }
|
||||
|
||||
private Color4 accentColour = Color4.White;
|
||||
|
||||
/// <summary>
|
||||
/// Used to colour the path.
|
||||
/// </summary>
|
||||
@@ -61,6 +63,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
}
|
||||
|
||||
private Color4 borderColour = Color4.White;
|
||||
|
||||
/// <summary>
|
||||
/// Used to colour the path border.
|
||||
/// </summary>
|
||||
@@ -85,6 +88,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
private Vector2 topLeftOffset;
|
||||
|
||||
private readonly Slider slider;
|
||||
|
||||
public SliderBody(Slider s)
|
||||
{
|
||||
slider = s;
|
||||
@@ -139,8 +143,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
var texture = new Texture(textureWidth, 1);
|
||||
|
||||
//initialise background
|
||||
var raw = new RawTexture(textureWidth, 1);
|
||||
var bytes = raw.Data;
|
||||
var raw = new Image<Rgba32>(textureWidth, 1);
|
||||
|
||||
const float aa_portion = 0.02f;
|
||||
const float border_portion = 0.128f;
|
||||
@@ -155,19 +158,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
|
||||
if (progress <= border_portion)
|
||||
{
|
||||
bytes[i * 4] = (byte)(BorderColour.R * 255);
|
||||
bytes[i * 4 + 1] = (byte)(BorderColour.G * 255);
|
||||
bytes[i * 4 + 2] = (byte)(BorderColour.B * 255);
|
||||
bytes[i * 4 + 3] = (byte)(Math.Min(progress / aa_portion, 1) * (BorderColour.A * 255));
|
||||
raw[i, 0] = new Rgba32(BorderColour.R, BorderColour.G, BorderColour.B, Math.Min(progress / aa_portion, 1) * BorderColour.A);
|
||||
}
|
||||
else
|
||||
{
|
||||
progress -= border_portion;
|
||||
|
||||
bytes[i * 4] = (byte)(AccentColour.R * 255);
|
||||
bytes[i * 4 + 1] = (byte)(AccentColour.G * 255);
|
||||
bytes[i * 4 + 2] = (byte)(AccentColour.B * 255);
|
||||
bytes[i * 4 + 3] = (byte)((opacity_at_edge - (opacity_at_edge - opacity_at_centre) * progress / gradient_portion) * (AccentColour.A * 255));
|
||||
raw[i, 0] = new Rgba32(AccentColour.R, AccentColour.G, AccentColour.B,
|
||||
(opacity_at_edge - (opacity_at_edge - opacity_at_centre) * progress / gradient_portion) * AccentColour.A);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Platform;
|
||||
@@ -62,6 +63,8 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
public override string[] HandledExtensions => new[] { ".osz" };
|
||||
|
||||
protected override string ImportFromStablePath => "Songs";
|
||||
|
||||
private readonly RulesetStore rulesets;
|
||||
|
||||
private readonly BeatmapStore beatmaps;
|
||||
@@ -72,11 +75,6 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
private readonly List<DownloadBeatmapSetRequest> currentDownloads = new List<DownloadBeatmapSetRequest>();
|
||||
|
||||
/// <summary>
|
||||
/// Set a storage with access to an osu-stable install for import purposes.
|
||||
/// </summary>
|
||||
public Func<Storage> GetStableStorage { private get; set; }
|
||||
|
||||
public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, APIAccess api, AudioManager audioManager, IIpcHost importHost = null)
|
||||
: base(storage, contextFactory, new BeatmapStore(contextFactory), importHost)
|
||||
{
|
||||
@@ -195,7 +193,7 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
downloadNotification.CompletionClickAction = () =>
|
||||
{
|
||||
PresentBeatmap?.Invoke(importedBeatmap);
|
||||
PresentCompletedImport(importedBeatmap.Yield());
|
||||
return true;
|
||||
};
|
||||
downloadNotification.State = ProgressNotificationState.Completed;
|
||||
@@ -231,6 +229,12 @@ namespace osu.Game.Beatmaps
|
||||
BeatmapDownloadBegan?.Invoke(request);
|
||||
}
|
||||
|
||||
protected override void PresentCompletedImport(IEnumerable<BeatmapSetInfo> imported)
|
||||
{
|
||||
base.PresentCompletedImport(imported);
|
||||
PresentBeatmap?.Invoke(imported.LastOrDefault());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an existing download request if it exists.
|
||||
/// </summary>
|
||||
@@ -311,27 +315,6 @@ namespace osu.Game.Beatmaps
|
||||
/// <returns>Results from the provided query.</returns>
|
||||
public IQueryable<BeatmapInfo> QueryBeatmaps(Expression<Func<BeatmapInfo, bool>> query) => beatmaps.Beatmaps.AsNoTracking().Where(query);
|
||||
|
||||
/// <summary>
|
||||
/// Denotes whether an osu-stable installation is present to perform automated imports from.
|
||||
/// </summary>
|
||||
public bool StableInstallationAvailable => GetStableStorage?.Invoke() != null;
|
||||
|
||||
/// <summary>
|
||||
/// This is a temporary method and will likely be replaced by a full-fledged (and more correctly placed) migration process in the future.
|
||||
/// </summary>
|
||||
public Task ImportFromStable()
|
||||
{
|
||||
var stable = GetStableStorage?.Invoke();
|
||||
|
||||
if (stable == null)
|
||||
{
|
||||
Logger.Log("No osu!stable installation available!", LoggingTarget.Information, LogLevel.Error);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
return Task.Factory.StartNew(() => Import(stable.GetDirectories("Songs").Select(f => stable.GetFullPath(f)).ToArray()), TaskCreationOptions.LongRunning);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a SHA-2 hash from the provided archive based on contained beatmap (.osu) file content.
|
||||
/// </summary>
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
try
|
||||
{
|
||||
return (textureStore ?? (textureStore = new LargeTextureStore(new RawTextureLoaderStore(store)))).Get(getPathForFile(Metadata.BackgroundFile));
|
||||
return (textureStore ?? (textureStore = new LargeTextureStore(new TextureLoaderStore(store)))).Get(getPathForFile(Metadata.BackgroundFile));
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using osu.Framework.IO.File;
|
||||
@@ -129,7 +130,6 @@ namespace osu.Game.Database
|
||||
List<TModel> imported = new List<TModel>();
|
||||
|
||||
int current = 0;
|
||||
int errors = 0;
|
||||
foreach (string path in paths)
|
||||
{
|
||||
if (notification.State == ProgressNotificationState.Cancelled)
|
||||
@@ -162,12 +162,29 @@ namespace osu.Game.Database
|
||||
{
|
||||
e = e.InnerException ?? e;
|
||||
Logger.Error(e, $@"Could not import ({Path.GetFileName(path)})");
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
notification.Text = errors > 0 ? $"Import complete with {errors} errors" : "Import successful!";
|
||||
notification.State = ProgressNotificationState.Completed;
|
||||
if (imported.Count == 0)
|
||||
{
|
||||
notification.Text = "Import failed!";
|
||||
notification.State = ProgressNotificationState.Cancelled;
|
||||
}
|
||||
else
|
||||
{
|
||||
notification.CompletionText = $"Imported {current} {typeof(TModel).Name.Replace("Info", "").ToLower()}s!";
|
||||
notification.CompletionClickAction += () =>
|
||||
{
|
||||
if (imported.Count > 0)
|
||||
PresentCompletedImport(imported);
|
||||
return true;
|
||||
};
|
||||
notification.State = ProgressNotificationState.Completed;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void PresentCompletedImport(IEnumerable<TModel> imported)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -283,7 +300,7 @@ namespace osu.Game.Database
|
||||
var notification = new ProgressNotification
|
||||
{
|
||||
Progress = 0,
|
||||
CompletionText = "Deleted all beatmaps!",
|
||||
CompletionText = $"Deleted all {typeof(TModel).Name.Replace("Info", "").ToLower()}s!",
|
||||
State = ProgressNotificationState.Active,
|
||||
};
|
||||
|
||||
@@ -385,6 +402,41 @@ namespace osu.Game.Database
|
||||
return fileInfos;
|
||||
}
|
||||
|
||||
#region osu-stable import
|
||||
|
||||
/// <summary>
|
||||
/// Set a storage with access to an osu-stable install for import purposes.
|
||||
/// </summary>
|
||||
public Func<Storage> GetStableStorage { private get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Denotes whether an osu-stable installation is present to perform automated imports from.
|
||||
/// </summary>
|
||||
public bool StableInstallationAvailable => GetStableStorage?.Invoke() != null;
|
||||
|
||||
/// <summary>
|
||||
/// The relative path from osu-stable's data directory to import items from.
|
||||
/// </summary>
|
||||
protected virtual string ImportFromStablePath => null;
|
||||
|
||||
/// <summary>
|
||||
/// This is a temporary method and will likely be replaced by a full-fledged (and more correctly placed) migration process in the future.
|
||||
/// </summary>
|
||||
public Task ImportFromStableAsync()
|
||||
{
|
||||
var stable = GetStableStorage?.Invoke();
|
||||
|
||||
if (stable == null)
|
||||
{
|
||||
Logger.Log("No osu!stable installation available!", LoggingTarget.Information, LogLevel.Error);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
return Task.Factory.StartNew(() => Import(stable.GetDirectories(ImportFromStablePath).Select(f => stable.GetFullPath(f)).ToArray()), TaskCreationOptions.LongRunning);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Create a barebones model from the provided archive.
|
||||
/// Actual expensive population should be done in <see cref="Populate"/>; this should just prepare for duplicate checking.
|
||||
|
||||
+4
-2
@@ -299,11 +299,13 @@ namespace osu.Game
|
||||
// This prevents the cursor from showing until we have a screen with CursorVisible = true
|
||||
MenuCursorContainer.CanShowCursor = currentScreen?.CursorVisible ?? false;
|
||||
|
||||
// hook up notifications to components.
|
||||
// todo: all archive managers should be able to be looped here.
|
||||
SkinManager.PostNotification = n => notifications?.Post(n);
|
||||
BeatmapManager.PostNotification = n => notifications?.Post(n);
|
||||
SkinManager.GetStableStorage = GetStorageForStableInstall;
|
||||
|
||||
BeatmapManager.PostNotification = n => notifications?.Post(n);
|
||||
BeatmapManager.GetStableStorage = GetStorageForStableInstall;
|
||||
|
||||
BeatmapManager.PresentBeatmap = PresentBeatmap;
|
||||
|
||||
AddRange(new Drawable[]
|
||||
|
||||
@@ -108,7 +108,9 @@ namespace osu.Game
|
||||
|
||||
dependencies.Cache(contextFactory = new DatabaseContextFactory(Host.Storage));
|
||||
|
||||
dependencies.Cache(new LargeTextureStore(new RawTextureLoaderStore(new NamespacedResourceStore<byte[]>(Resources, @"Textures"))));
|
||||
var largeStore = new LargeTextureStore(new TextureLoaderStore(new NamespacedResourceStore<byte[]>(Resources, @"Textures")));
|
||||
largeStore.AddStore(new TextureLoaderStore(new OnlineStore()));
|
||||
dependencies.Cache(largeStore);
|
||||
|
||||
dependencies.CacheAs(this);
|
||||
dependencies.Cache(LocalConfig);
|
||||
|
||||
@@ -104,8 +104,6 @@ namespace osu.Game.Overlays.Direct
|
||||
beatmaps.ItemAdded += setAdded;
|
||||
}
|
||||
|
||||
public override bool DisposeOnDeathRemoval => true;
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
@@ -118,9 +118,9 @@ namespace osu.Game.Overlays.MedalSplash
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, TextureStore textures)
|
||||
private void load(OsuColour colours, TextureStore textures, LargeTextureStore largeTextures)
|
||||
{
|
||||
medalSprite.Texture = textures.Get(medal.ImageUrl);
|
||||
medalSprite.Texture = largeTextures.Get(medal.ImageUrl);
|
||||
medalGlow.Texture = textures.Get(@"MedalSplash/medal-glow");
|
||||
description.Colour = colours.BlueLight;
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ namespace osu.Game.Overlays.Notifications
|
||||
public Action<Notification> CompletionTarget { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An action to complete when the completion notification is clicked.
|
||||
/// An action to complete when the completion notification is clicked. Return true to close.
|
||||
/// </summary>
|
||||
public Func<bool> CompletionClickAction;
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore textures)
|
||||
private void load(LargeTextureStore textures)
|
||||
{
|
||||
Child = new Sprite
|
||||
{
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore textures)
|
||||
private void load(LargeTextureStore textures)
|
||||
{
|
||||
sprite.Texture = textures.Get(url);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
// 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.Drawing;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
|
||||
@@ -15,21 +19,36 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
private FillFlowContainer letterboxSettings;
|
||||
|
||||
private Bindable<bool> letterboxing;
|
||||
private Bindable<Size> sizeFullscreen;
|
||||
|
||||
private OsuGameBase game;
|
||||
private SettingsDropdown<Size> resolutionDropdown;
|
||||
private SettingsEnumDropdown<WindowMode> windowModeDropdown;
|
||||
|
||||
private const int transition_duration = 400;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(FrameworkConfigManager config)
|
||||
private void load(FrameworkConfigManager config, OsuGameBase game)
|
||||
{
|
||||
this.game = game;
|
||||
|
||||
letterboxing = config.GetBindable<bool>(FrameworkSetting.Letterboxing);
|
||||
sizeFullscreen = config.GetBindable<Size>(FrameworkSetting.SizeFullscreen);
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new SettingsEnumDropdown<WindowMode>
|
||||
windowModeDropdown = new SettingsEnumDropdown<WindowMode>
|
||||
{
|
||||
LabelText = "Screen mode",
|
||||
Bindable = config.GetBindable<WindowMode>(FrameworkSetting.WindowMode),
|
||||
},
|
||||
resolutionDropdown = new SettingsDropdown<Size>
|
||||
{
|
||||
LabelText = "Resolution",
|
||||
ShowsDefaultIndicator = false,
|
||||
Items = getResolutions(),
|
||||
Bindable = sizeFullscreen
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Letterboxing",
|
||||
@@ -62,15 +81,39 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
},
|
||||
};
|
||||
|
||||
letterboxing.ValueChanged += isVisible =>
|
||||
windowModeDropdown.Bindable.BindValueChanged(windowMode =>
|
||||
{
|
||||
if (windowMode == WindowMode.Fullscreen)
|
||||
{
|
||||
resolutionDropdown.Show();
|
||||
sizeFullscreen.TriggerChange();
|
||||
}
|
||||
else
|
||||
resolutionDropdown.Hide();
|
||||
}, true);
|
||||
|
||||
letterboxing.BindValueChanged(isVisible =>
|
||||
{
|
||||
letterboxSettings.ClearTransforms();
|
||||
letterboxSettings.AutoSizeAxes = isVisible ? Axes.Y : Axes.None;
|
||||
|
||||
if (!isVisible)
|
||||
letterboxSettings.ResizeHeightTo(0, transition_duration, Easing.OutQuint);
|
||||
};
|
||||
letterboxing.TriggerChange();
|
||||
}, true);
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string, Size>> getResolutions()
|
||||
{
|
||||
var resolutions = new KeyValuePair<string, Size>("Default", new Size(9999, 9999)).Yield();
|
||||
|
||||
if (game.Window != null)
|
||||
resolutions = resolutions.Concat(game.Window.AvailableResolutions
|
||||
.Where(r => r.Width >= 800 && r.Height >= 600)
|
||||
.OrderByDescending(r => r.Width)
|
||||
.ThenByDescending(r => r.Height)
|
||||
.Select(res => new KeyValuePair<string, Size>($"{res.Width}x{res.Height}", new Size(res.Width, res.Height)))
|
||||
.Distinct()).ToList();
|
||||
return resolutions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
{
|
||||
@@ -20,7 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
protected override string Header => "General";
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(BeatmapManager beatmaps, DialogOverlay dialogOverlay)
|
||||
private void load(BeatmapManager beatmaps, SkinManager skins, DialogOverlay dialogOverlay)
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@@ -30,7 +31,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
Action = () =>
|
||||
{
|
||||
importButton.Enabled.Value = false;
|
||||
beatmaps.ImportFromStable().ContinueWith(t => Schedule(() => importButton.Enabled.Value = true));
|
||||
beatmaps.ImportFromStableAsync().ContinueWith(t => Schedule(() => importButton.Enabled.Value = true));
|
||||
}
|
||||
},
|
||||
deleteButton = new DangerousSettingsButton
|
||||
@@ -45,6 +46,27 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
}));
|
||||
}
|
||||
},
|
||||
importButton = new SettingsButton
|
||||
{
|
||||
Text = "Import skins from stable",
|
||||
Action = () =>
|
||||
{
|
||||
importButton.Enabled.Value = false;
|
||||
skins.ImportFromStableAsync().ContinueWith(t => Schedule(() => importButton.Enabled.Value = true));
|
||||
}
|
||||
},
|
||||
deleteButton = new DangerousSettingsButton
|
||||
{
|
||||
Text = "Delete ALL skins",
|
||||
Action = () =>
|
||||
{
|
||||
dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() =>
|
||||
{
|
||||
deleteButton.Enabled.Value = false;
|
||||
Task.Run(() => skins.Delete(skins.GetAllUserSkins())).ContinueWith(t => Schedule(() => deleteButton.Enabled.Value = true));
|
||||
}));
|
||||
}
|
||||
},
|
||||
restoreButton = new SettingsButton
|
||||
{
|
||||
Text = "Restore all hidden difficulties",
|
||||
|
||||
@@ -51,10 +51,10 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
},
|
||||
};
|
||||
|
||||
skins.ItemAdded += onItemsChanged;
|
||||
skins.ItemRemoved += onItemsChanged;
|
||||
skins.ItemAdded += itemAdded;
|
||||
skins.ItemRemoved += itemRemoved;
|
||||
|
||||
reloadSkins();
|
||||
skinDropdown.Items = skins.GetAllUsableSkins().Select(s => new KeyValuePair<string, int>(s.ToString(), s.ID));
|
||||
|
||||
var skinBindable = config.GetBindable<int>(OsuSetting.Skin);
|
||||
|
||||
@@ -65,9 +65,8 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
skinDropdown.Bindable = skinBindable;
|
||||
}
|
||||
|
||||
private void reloadSkins() => skinDropdown.Items = skins.GetAllUsableSkins().Select(s => new KeyValuePair<string, int>(s.ToString(), s.ID));
|
||||
|
||||
private void onItemsChanged(SkinInfo _) => Schedule(reloadSkins);
|
||||
private void itemRemoved(SkinInfo s) => skinDropdown.Items = skinDropdown.Items.Where(i => i.Value != s.ID);
|
||||
private void itemAdded(SkinInfo s) => skinDropdown.Items = skinDropdown.Items.Append(new KeyValuePair<string, int>(s.ToString(), s.ID));
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
@@ -75,8 +74,8 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
|
||||
if (skins != null)
|
||||
{
|
||||
skins.ItemAdded -= onItemsChanged;
|
||||
skins.ItemRemoved -= onItemsChanged;
|
||||
skins.ItemAdded -= itemAdded;
|
||||
skins.ItemRemoved -= itemRemoved;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace osu.Game.Screens.Ranking
|
||||
{
|
||||
public class ResultsPageScore : ResultsPage
|
||||
{
|
||||
private Container scoreContainer;
|
||||
private ScoreCounter scoreCounter;
|
||||
|
||||
public ResultsPageScore(Score score, WorkingBeatmap beatmap) : base(score, beatmap) { }
|
||||
@@ -76,7 +77,7 @@ namespace osu.Game.Screens.Ranking
|
||||
Size = new Vector2(150, 60),
|
||||
Margin = new MarginPadding(20),
|
||||
},
|
||||
new Container
|
||||
scoreContainer = new Container
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
@@ -92,8 +93,8 @@ namespace osu.Game.Screens.Ranking
|
||||
},
|
||||
scoreCounter = new SlowScoreCounter(6)
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Colour = colours.PinkDarker,
|
||||
Y = 10,
|
||||
TextSize = 56,
|
||||
@@ -185,6 +186,13 @@ namespace osu.Game.Screens.Ranking
|
||||
});
|
||||
}
|
||||
|
||||
protected override void UpdateAfterChildren()
|
||||
{
|
||||
base.UpdateAfterChildren();
|
||||
|
||||
scoreCounter.Scale = new Vector2(Math.Min(1f, (scoreContainer.DrawWidth - 20) / scoreCounter.DrawWidth));
|
||||
}
|
||||
|
||||
private class DrawableScoreStatistic : Container
|
||||
{
|
||||
private readonly KeyValuePair<HitResult, object> statistic;
|
||||
@@ -368,7 +376,7 @@ namespace osu.Game.Screens.Ranking
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore textures)
|
||||
private void load(LargeTextureStore textures)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(user.CoverUrl))
|
||||
cover.Texture = textures.Get(user.CoverUrl);
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace osu.Game.Screens.Select
|
||||
public ImportFromStablePopup(Action importFromStable)
|
||||
{
|
||||
HeaderText = @"You have no beatmaps!";
|
||||
BodyText = "An existing copy of osu! was found, though.\nWould you like to import your beatmaps?";
|
||||
BodyText = "An existing copy of osu! was found, though.\nWould you like to import your beatmaps (and skins)?";
|
||||
|
||||
Icon = FontAwesome.fa_plane;
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using OpenTK.Input;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
@@ -20,6 +19,7 @@ using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Screens.Edit;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Screens.Select
|
||||
{
|
||||
@@ -55,7 +55,7 @@ namespace osu.Game.Screens.Select
|
||||
private readonly Bindable<IEnumerable<Mod>> selectedMods = new Bindable<IEnumerable<Mod>>(new Mod[] { });
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OsuColour colours, AudioManager audio, BeatmapManager beatmaps, DialogOverlay dialogOverlay, Bindable<IEnumerable<Mod>> selectedMods)
|
||||
private void load(OsuColour colours, AudioManager audio, BeatmapManager beatmaps, SkinManager skins, DialogOverlay dialogOverlay, Bindable<IEnumerable<Mod>> selectedMods)
|
||||
{
|
||||
if (selectedMods != null) this.selectedMods.BindTo(selectedMods);
|
||||
|
||||
@@ -78,7 +78,10 @@ namespace osu.Game.Screens.Select
|
||||
// if we have no beatmaps but osu-stable is found, let's prompt the user to import.
|
||||
if (!beatmaps.GetAllUsableBeatmapSets().Any() && beatmaps.StableInstallationAvailable)
|
||||
dialogOverlay.Push(new ImportFromStablePopup(() =>
|
||||
Task.Factory.StartNew(beatmaps.ImportFromStable, TaskCreationOptions.LongRunning)));
|
||||
{
|
||||
beatmaps.ImportFromStableAsync();
|
||||
skins.ImportFromStableAsync();
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace osu.Game.Screens.Tournament
|
||||
|
||||
TextureStore flagStore = new TextureStore();
|
||||
// Local flag store
|
||||
flagStore.AddStore(new RawTextureLoaderStore(new NamespacedResourceStore<byte[]>(new StorageBackedResourceStore(storage), "Drawings")));
|
||||
flagStore.AddStore(new TextureLoaderStore(new NamespacedResourceStore<byte[]>(new StorageBackedResourceStore(storage), "Drawings")));
|
||||
// Default texture store
|
||||
flagStore.AddStore(textures);
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace osu.Game.Skinning
|
||||
Configuration = new SkinConfiguration();
|
||||
|
||||
Samples = audioManager.GetSampleManager(storage);
|
||||
Textures = new TextureStore(new RawTextureLoaderStore(storage));
|
||||
Textures = new TextureStore(new TextureLoaderStore(storage));
|
||||
}
|
||||
|
||||
public override Drawable GetDrawableComponent(string componentName)
|
||||
|
||||
@@ -26,17 +26,25 @@ namespace osu.Game.Skinning
|
||||
|
||||
public override string[] HandledExtensions => new[] { ".osk" };
|
||||
|
||||
protected override string ImportFromStablePath => "Skins";
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all usable <see cref="SkinInfo"/>s.
|
||||
/// Returns a list of all usable <see cref="SkinInfo"/>s. Includes the special default skin plus all skins from <see cref="GetAllUserSkins"/>.
|
||||
/// </summary>
|
||||
/// <returns>A list of available <see cref="SkinInfo"/>.</returns>
|
||||
public List<SkinInfo> GetAllUsableSkins()
|
||||
{
|
||||
var userSkins = ModelStore.ConsumableItems.Where(s => !s.DeletePending).ToList();
|
||||
var userSkins = GetAllUserSkins();
|
||||
userSkins.Insert(0, SkinInfo.Default);
|
||||
return userSkins;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all usable <see cref="SkinInfo"/>s that have been loaded by the user.
|
||||
/// </summary>
|
||||
/// <returns>A list of available <see cref="SkinInfo"/>.</returns>
|
||||
public List<SkinInfo> GetAllUserSkins() => ModelStore.ConsumableItems.Where(s => !s.DeletePending).ToList();
|
||||
|
||||
protected override SkinInfo CreateModel(ArchiveReader archive) => new SkinInfo
|
||||
{
|
||||
Name = archive.Name
|
||||
@@ -85,6 +93,13 @@ namespace osu.Game.Skinning
|
||||
{
|
||||
this.audio = audio;
|
||||
|
||||
ItemRemoved += removedInfo =>
|
||||
{
|
||||
// check the removed skin is not the current user choice. if it is, switch back to default.
|
||||
if (removedInfo.ID == CurrentSkinInfo.Value.ID)
|
||||
CurrentSkinInfo.Value = SkinInfo.Default;
|
||||
};
|
||||
|
||||
CurrentSkinInfo.ValueChanged += info => CurrentSkin.Value = GetSkin(info);
|
||||
CurrentSkin.ValueChanged += skin =>
|
||||
{
|
||||
@@ -93,16 +108,6 @@ namespace osu.Game.Skinning
|
||||
|
||||
SourceChanged?.Invoke();
|
||||
};
|
||||
|
||||
// migrate older imports which didn't have access to skin.ini
|
||||
using (ContextFactory.GetForWrite())
|
||||
{
|
||||
foreach (var skinInfo in ModelStore.ConsumableItems.Where(s => s.Name.EndsWith(".osk")))
|
||||
{
|
||||
populate(skinInfo);
|
||||
Update(skinInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -22,7 +22,6 @@ namespace osu.Game.Storyboards.Drawables
|
||||
public override bool HandleMouseInput => false;
|
||||
|
||||
private bool passing = true;
|
||||
|
||||
public bool Passing
|
||||
{
|
||||
get { return passing; }
|
||||
@@ -37,7 +36,6 @@ namespace osu.Game.Storyboards.Drawables
|
||||
public override bool RemoveCompletedTransforms => false;
|
||||
|
||||
private DependencyContainer dependencies;
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) =>
|
||||
dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
|
||||
@@ -59,7 +57,7 @@ namespace osu.Game.Storyboards.Drawables
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(FileStore fileStore)
|
||||
{
|
||||
dependencies.Cache(new TextureStore(new RawTextureLoaderStore(fileStore.Store), false, scaleAdjust: 1));
|
||||
dependencies.Cache(new TextureStore(new TextureLoaderStore(fileStore.Store), false, scaleAdjust: 1));
|
||||
|
||||
foreach (var layer in Storyboard.Layers)
|
||||
Add(layer.CreateDrawable());
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace osu.Game.Users
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore textures)
|
||||
private void load(LargeTextureStore textures)
|
||||
{
|
||||
if (textures == null)
|
||||
throw new ArgumentNullException(nameof(textures));
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace osu.Game.Users
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore textures)
|
||||
private void load(LargeTextureStore textures)
|
||||
{
|
||||
if (textures == null)
|
||||
throw new ArgumentNullException(nameof(textures));
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2018.906.1" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2018.910.1" />
|
||||
<PackageReference Include="SharpCompress" Version="0.22.0" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
|
||||
Reference in New Issue
Block a user