Merge branch 'master' into musiccontroller-canbeatmapchange

This commit is contained in:
Dean Herbert
2017-08-01 11:54:05 +09:00
committed by GitHub
248 changed files with 2485 additions and 2045 deletions

View File

@ -3,7 +3,6 @@
using OpenTK.Graphics;
using osu.Game.Beatmaps.Timing;
using osu.Game.Database;
using osu.Game.Rulesets.Objects;
using System.Collections.Generic;
using System.Linq;

View File

@ -3,7 +3,7 @@
using SQLite.Net.Attributes;
namespace osu.Game.Database
namespace osu.Game.Beatmaps
{
public class BeatmapDifficulty
{

View File

@ -1,14 +1,15 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using Newtonsoft.Json;
using osu.Game.IO.Serialization;
using SQLite.Net.Attributes;
using SQLiteNetExtensions.Attributes;
using System;
using System.Linq;
using Newtonsoft.Json;
using osu.Game.IO.Serialization;
using osu.Game.Rulesets;
using SQLite.Net.Attributes;
using SQLiteNetExtensions.Attributes;
namespace osu.Game.Database
namespace osu.Game.Beatmaps
{
public class BeatmapInfo : IEquatable<BeatmapInfo>, IJsonSerializable
{
@ -60,7 +61,7 @@ namespace osu.Game.Database
[ForeignKey(typeof(RulesetInfo))]
public int RulesetID { get; set; }
[OneToOne(CascadeOperations = CascadeOperation.All)]
[OneToOne(CascadeOperations = CascadeOperation.CascadeRead)]
public RulesetInfo Ruleset { get; set; }
public bool LetterboxInBreaks { get; set; }
@ -94,11 +95,11 @@ namespace osu.Game.Database
}
public bool AudioEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null &&
BeatmapSet.Path == other.BeatmapSet.Path &&
BeatmapSet.Hash == other.BeatmapSet.Hash &&
(Metadata ?? BeatmapSet.Metadata).AudioFile == (other.Metadata ?? other.BeatmapSet.Metadata).AudioFile;
public bool BackgroundEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null &&
BeatmapSet.Path == other.BeatmapSet.Path &&
BeatmapSet.Hash == other.BeatmapSet.Hash &&
(Metadata ?? BeatmapSet.Metadata).BackgroundFile == (other.Metadata ?? other.BeatmapSet.Metadata).BackgroundFile;
}
}

View File

@ -0,0 +1,499 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using Ionic.Zip;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions;
using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.IO;
using osu.Game.IO;
using osu.Game.IPC;
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets;
using SQLite.Net;
namespace osu.Game.Beatmaps
{
/// <summary>
/// Handles the storage and retrieval of Beatmaps/WorkingBeatmaps.
/// </summary>
public class BeatmapManager
{
/// <summary>
/// Fired when a new <see cref="BeatmapSetInfo"/> becomes available in the database.
/// </summary>
public event Action<BeatmapSetInfo> BeatmapSetAdded;
/// <summary>
/// Fired when a <see cref="BeatmapSetInfo"/> is removed from the database.
/// </summary>
public event Action<BeatmapSetInfo> BeatmapSetRemoved;
/// <summary>
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
/// </summary>
public WorkingBeatmap DefaultBeatmap { private get; set; }
private readonly Storage storage;
private readonly FileStore files;
private readonly RulesetStore rulesets;
private readonly BeatmapStore beatmaps;
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
private BeatmapIPCChannel ipc;
/// <summary>
/// Set an endpoint for notifications to be posted to.
/// </summary>
public Action<Notification> PostNotification { private get; set; }
public BeatmapManager(Storage storage, FileStore files, SQLiteConnection connection, RulesetStore rulesets, IIpcHost importHost = null)
{
beatmaps = new BeatmapStore(connection);
beatmaps.BeatmapSetAdded += s => BeatmapSetAdded?.Invoke(s);
beatmaps.BeatmapSetRemoved += s => BeatmapSetRemoved?.Invoke(s);
this.storage = storage;
this.files = files;
this.rulesets = rulesets;
if (importHost != null)
ipc = new BeatmapIPCChannel(importHost, this);
}
/// <summary>
/// Import one or more <see cref="BeatmapSetInfo"/> from filesystem <paramref name="paths"/>.
/// This will post a notification tracking import progress.
/// </summary>
/// <param name="paths">One or more beatmap locations on disk.</param>
public void Import(params string[] paths)
{
var notification = new ProgressNotification
{
Text = "Beatmap import is initialising...",
Progress = 0,
State = ProgressNotificationState.Active,
};
PostNotification?.Invoke(notification);
int i = 0;
foreach (string path in paths)
{
if (notification.State == ProgressNotificationState.Cancelled)
// user requested abort
return;
try
{
notification.Text = $"Importing ({i} of {paths.Length})\n{Path.GetFileName(path)}";
using (ArchiveReader reader = getReaderFrom(path))
Import(reader);
notification.Progress = (float)++i / paths.Length;
// We may or may not want to delete the file depending on where it is stored.
// e.g. reconstructing/repairing database with beatmaps from default storage.
// Also, not always a single file, i.e. for LegacyFilesystemReader
// TODO: Add a check to prevent files from storage to be deleted.
try
{
if (File.Exists(path))
File.Delete(path);
}
catch (Exception e)
{
Logger.Error(e, $@"Could not delete original file after import ({Path.GetFileName(path)})");
}
}
catch (Exception e)
{
e = e.InnerException ?? e;
Logger.Error(e, @"Could not import beatmap set");
}
}
notification.State = ProgressNotificationState.Completed;
}
private readonly object importLock = new object();
/// <summary>
/// Import a beatmap from an <see cref="ArchiveReader"/>.
/// </summary>
/// <param name="archiveReader">The beatmap to be imported.</param>
public BeatmapSetInfo Import(ArchiveReader archiveReader)
{
// let's only allow one concurrent import at a time for now.
lock (importLock)
{
BeatmapSetInfo set = importToStorage(archiveReader);
Import(set);
return set;
}
}
/// <summary>
/// Import a beatmap from a <see cref="BeatmapSetInfo"/>.
/// </summary>
/// <param name="beatmapSetInfo">The beatmap to be imported.</param>
public void Import(BeatmapSetInfo beatmapSetInfo)
{
// If we have an ID then we already exist in the database.
if (beatmapSetInfo.ID != 0) return;
lock (beatmaps)
beatmaps.Add(beatmapSetInfo);
}
/// <summary>
/// Delete a beatmap from the manager.
/// Is a no-op for already deleted beatmaps.
/// </summary>
/// <param name="beatmapSet">The beatmap to delete.</param>
public void Delete(BeatmapSetInfo beatmapSet)
{
lock (beatmaps)
if (!beatmaps.Delete(beatmapSet)) return;
if (!beatmapSet.Protected)
files.Dereference(beatmapSet.Files.Select(f => f.FileInfo));
}
/// <summary>
/// Returns a <see cref="BeatmapSetInfo"/> to a usable state if it has previously been deleted but not yet purged.
/// Is a no-op for already usable beatmaps.
/// </summary>
/// <param name="beatmapSet">The beatmap to restore.</param>
public void Undelete(BeatmapSetInfo beatmapSet)
{
lock (beatmaps)
if (!beatmaps.Undelete(beatmapSet)) return;
if (!beatmapSet.Protected)
files.Reference(beatmapSet.Files.Select(f => f.FileInfo));
}
/// <summary>
/// Retrieve a <see cref="WorkingBeatmap"/> instance for the provided <see cref="BeatmapInfo"/>
/// </summary>
/// <param name="beatmapInfo">The beatmap to lookup.</param>
/// <param name="previous">The currently loaded <see cref="WorkingBeatmap"/>. Allows for optimisation where elements are shared with the new beatmap.</param>
/// <returns>A <see cref="WorkingBeatmap"/> instance correlating to the provided <see cref="BeatmapInfo"/>.</returns>
public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null)
{
if (beatmapInfo == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo)
return DefaultBeatmap;
lock (beatmaps)
beatmaps.Populate(beatmapInfo);
if (beatmapInfo.BeatmapSet == null)
throw new InvalidOperationException($@"Beatmap set {beatmapInfo.BeatmapSetInfoID} is not in the local database.");
if (beatmapInfo.Metadata == null)
beatmapInfo.Metadata = beatmapInfo.BeatmapSet.Metadata;
WorkingBeatmap working = new BeatmapManagerWorkingBeatmap(files.Store, beatmapInfo);
previous?.TransferTo(working);
return working;
}
/// <summary>
/// Reset the manager to an empty state.
/// </summary>
public void Reset()
{
lock (beatmaps)
beatmaps.Reset();
}
/// <summary>
/// Perform a lookup query on available <see cref="BeatmapSetInfo"/>s.
/// </summary>
/// <param name="query">The query.</param>
/// <returns>The first result for the provided query, or null if no results were found.</returns>
public BeatmapSetInfo QueryBeatmapSet(Func<BeatmapSetInfo, bool> query)
{
lock (beatmaps)
{
BeatmapSetInfo set = beatmaps.Query<BeatmapSetInfo>().FirstOrDefault(query);
if (set != null)
beatmaps.Populate(set);
return set;
}
}
/// <summary>
/// Perform a lookup query on available <see cref="BeatmapSetInfo"/>s.
/// </summary>
/// <param name="query">The query.</param>
/// <returns>Results from the provided query.</returns>
public List<BeatmapSetInfo> QueryBeatmapSets(Expression<Func<BeatmapSetInfo, bool>> query)
{
lock (beatmaps) return beatmaps.QueryAndPopulate(query);
}
/// <summary>
/// Perform a lookup query on available <see cref="BeatmapInfo"/>s.
/// </summary>
/// <param name="query">The query.</param>
/// <returns>The first result for the provided query, or null if no results were found.</returns>
public BeatmapInfo QueryBeatmap(Func<BeatmapInfo, bool> query)
{
lock (beatmaps)
{
BeatmapInfo set = beatmaps.Query<BeatmapInfo>().FirstOrDefault(query);
if (set != null)
beatmaps.Populate(set);
return set;
}
}
/// <summary>
/// Perform a lookup query on available <see cref="BeatmapInfo"/>s.
/// </summary>
/// <param name="query">The query.</param>
/// <returns>Results from the provided query.</returns>
public List<BeatmapInfo> QueryBeatmaps(Expression<Func<BeatmapInfo, bool>> query)
{
lock (beatmaps) return beatmaps.QueryAndPopulate(query);
}
/// <summary>
/// Creates an <see cref="ArchiveReader"/> from a valid storage path.
/// </summary>
/// <param name="path">A file or folder path resolving the beatmap content.</param>
/// <returns>A reader giving access to the beatmap's content.</returns>
private ArchiveReader getReaderFrom(string path)
{
if (ZipFile.IsZipFile(path))
return new OszArchiveReader(storage.GetStream(path));
else
return new LegacyFilesystemReader(path);
}
/// <summary>
/// Import a beamap into our local <see cref="FileStore"/> storage.
/// If the beatmap is already imported, the existing instance will be returned.
/// </summary>
/// <param name="reader">The beatmap archive to be read.</param>
/// <returns>The imported beatmap, or an existing instance if it is already present.</returns>
private BeatmapSetInfo importToStorage(ArchiveReader reader)
{
// for now, concatenate all .osu files in the set to create a unique hash.
MemoryStream hashable = new MemoryStream();
foreach (string file in reader.Filenames.Where(f => f.EndsWith(".osu")))
using (Stream s = reader.GetStream(file))
s.CopyTo(hashable);
var hash = hashable.ComputeSHA2Hash();
// check if this beatmap has already been imported and exit early if so.
BeatmapSetInfo beatmapSet;
lock (beatmaps)
beatmapSet = beatmaps.QueryAndPopulate<BeatmapSetInfo>(b => b.Hash == hash).FirstOrDefault();
if (beatmapSet != null)
{
Undelete(beatmapSet);
return beatmapSet;
}
List<BeatmapSetFileInfo> fileInfos = new List<BeatmapSetFileInfo>();
// import files to manager
foreach (string file in reader.Filenames)
using (Stream s = reader.GetStream(file))
fileInfos.Add(new BeatmapSetFileInfo
{
Filename = file,
FileInfo = files.Add(s)
});
BeatmapMetadata metadata;
using (var stream = new StreamReader(reader.GetStream(reader.Filenames.First(f => f.EndsWith(".osu")))))
metadata = BeatmapDecoder.GetDecoder(stream).Decode(stream).Metadata;
beatmapSet = new BeatmapSetInfo
{
OnlineBeatmapSetID = metadata.OnlineBeatmapSetID,
Beatmaps = new List<BeatmapInfo>(),
Hash = hash,
Files = fileInfos,
Metadata = metadata
};
var mapNames = reader.Filenames.Where(f => f.EndsWith(".osu"));
foreach (var name in mapNames)
{
using (var raw = reader.GetStream(name))
using (var ms = new MemoryStream()) //we need a memory stream so we can seek and shit
using (var sr = new StreamReader(ms))
{
raw.CopyTo(ms);
ms.Position = 0;
var decoder = BeatmapDecoder.GetDecoder(sr);
Beatmap beatmap = decoder.Decode(sr);
beatmap.BeatmapInfo.Path = name;
beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash();
// TODO: Diff beatmap metadata with set metadata and leave it here if necessary
beatmap.BeatmapInfo.Metadata = null;
// TODO: this should be done in a better place once we actually need to dynamically update it.
beatmap.BeatmapInfo.Ruleset = rulesets.Query<RulesetInfo>().FirstOrDefault(r => r.ID == beatmap.BeatmapInfo.RulesetID);
beatmap.BeatmapInfo.StarDifficulty = rulesets.Query<RulesetInfo>().FirstOrDefault(r => r.ID == beatmap.BeatmapInfo.RulesetID)?.CreateInstance()?.CreateDifficultyCalculator(beatmap)
.Calculate() ?? 0;
beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo);
}
}
return beatmapSet;
}
/// <summary>
/// Returns a list of all usable <see cref="BeatmapSetInfo"/>s.
/// </summary>
/// <param name="populate">Whether returned objects should be pre-populated with all data.</param>
/// <returns>A list of available <see cref="BeatmapSetInfo"/>.</returns>
public List<BeatmapSetInfo> GetAllUsableBeatmapSets(bool populate = true)
{
lock (beatmaps)
{
if (populate)
return beatmaps.QueryAndPopulate<BeatmapSetInfo>(b => !b.DeletePending).ToList();
else
return beatmaps.Query<BeatmapSetInfo>(b => !b.DeletePending).ToList();
}
}
protected class BeatmapManagerWorkingBeatmap : WorkingBeatmap
{
private readonly IResourceStore<byte[]> store;
public BeatmapManagerWorkingBeatmap(IResourceStore<byte[]> store, BeatmapInfo beatmapInfo)
: base(beatmapInfo)
{
this.store = store;
}
protected override Beatmap GetBeatmap()
{
try
{
Beatmap beatmap;
BeatmapDecoder decoder;
using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path))))
{
decoder = BeatmapDecoder.GetDecoder(stream);
beatmap = decoder.Decode(stream);
}
if (beatmap == null || BeatmapSetInfo.StoryboardFile == null)
return beatmap;
using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile))))
decoder.Decode(stream, beatmap);
return beatmap;
}
catch { return null; }
}
private string getPathForFile(string filename) => BeatmapSetInfo.Files.First(f => f.Filename == filename).FileInfo.StoragePath;
protected override Texture GetBackground()
{
if (Metadata?.BackgroundFile == null)
return null;
try
{
return new TextureStore(new RawTextureLoaderStore(store), false).Get(getPathForFile(Metadata.BackgroundFile));
}
catch { return null; }
}
protected override Track GetTrack()
{
try
{
var trackData = store.GetStream(getPathForFile(Metadata.AudioFile));
return trackData == null ? null : new TrackBass(trackData);
}
catch { return new TrackVirtual(); }
}
}
public void ImportFromStable()
{
string stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"osu!", "Songs");
if (!Directory.Exists(stableInstallPath))
stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".osu", "Songs");
if (!Directory.Exists(stableInstallPath))
{
Logger.Log("Couldn't find an osu!stable installation!", LoggingTarget.Information, LogLevel.Error);
return;
}
Import(Directory.GetDirectories(stableInstallPath));
}
public void DeleteAll()
{
var maps = GetAllUsableBeatmapSets().ToArray();
if (maps.Length == 0) return;
var notification = new ProgressNotification
{
Progress = 0,
State = ProgressNotificationState.Active,
};
PostNotification?.Invoke(notification);
int i = 0;
foreach (var b in maps)
{
if (notification.State == ProgressNotificationState.Cancelled)
// user requested abort
return;
notification.Text = $"Deleting ({i} of {maps.Length})";
notification.Progress = (float)++i / maps.Length;
Delete(b);
}
notification.State = ProgressNotificationState.Completed;
}
}
}

View File

@ -5,7 +5,7 @@ using System.Linq;
using Newtonsoft.Json;
using SQLite.Net.Attributes;
namespace osu.Game.Database
namespace osu.Game.Beatmaps
{
public class BeatmapMetadata
{

View File

@ -4,7 +4,7 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace osu.Game.Database
namespace osu.Game.Beatmaps
{
/// <summary>
/// Beatmap metrics based on acculumated online data from community plays.

View File

@ -3,7 +3,7 @@
using Newtonsoft.Json;
namespace osu.Game.Database
namespace osu.Game.Beatmaps
{
/// <summary>
/// Beatmap info retrieved for previewing locally without having the beatmap downloaded.

View File

@ -0,0 +1,27 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.IO;
using SQLite.Net.Attributes;
using SQLiteNetExtensions.Attributes;
namespace osu.Game.Beatmaps
{
public class BeatmapSetFileInfo
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
[ForeignKey(typeof(BeatmapSetInfo)), NotNull]
public int BeatmapSetInfoID { get; set; }
[ForeignKey(typeof(FileInfo)), NotNull]
public int FileInfoID { get; set; }
[OneToOne(CascadeOperations = CascadeOperation.CascadeRead)]
public FileInfo FileInfo { get; set; }
[NotNull]
public string Filename { get; set; }
}
}

View File

@ -6,7 +6,7 @@ using System.Linq;
using SQLite.Net.Attributes;
using SQLiteNetExtensions.Attributes;
namespace osu.Game.Database
namespace osu.Game.Beatmaps
{
public class BeatmapSetInfo
{
@ -34,8 +34,11 @@ namespace osu.Game.Database
public string Hash { get; set; }
public string Path { get; set; }
public string StoryboardFile => Files.FirstOrDefault(f => f.Filename.EndsWith(".osb"))?.Filename;
public string StoryboardFile { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<BeatmapSetFileInfo> Files { get; set; }
public bool Protected { get; set; }
}
}

View File

@ -3,7 +3,7 @@
using Newtonsoft.Json;
namespace osu.Game.Database
namespace osu.Game.Beatmaps
{
/// <summary>
/// Beatmap set info retrieved for previewing locally without having the set downloaded.

View File

@ -0,0 +1,152 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Logging;
using osu.Game.Database;
using SQLite.Net;
using SQLiteNetExtensions.Extensions;
namespace osu.Game.Beatmaps
{
/// <summary>
/// Handles the storage and retrieval of Beatmaps/BeatmapSets to the database backing
/// </summary>
public class BeatmapStore : DatabaseBackedStore
{
public event Action<BeatmapSetInfo> BeatmapSetAdded;
public event Action<BeatmapSetInfo> BeatmapSetRemoved;
/// <summary>
/// The current version of this store. Used for migrations (see <see cref="PerformMigration(int, int)"/>).
/// The initial version is 1.
/// </summary>
protected override int StoreVersion => 2;
public BeatmapStore(SQLiteConnection connection)
: base(connection)
{
}
protected override Type[] ValidTypes => new[]
{
typeof(BeatmapSetInfo),
typeof(BeatmapInfo),
typeof(BeatmapMetadata),
typeof(BeatmapDifficulty),
};
protected override void Prepare(bool reset = false)
{
if (reset)
{
Connection.DropTable<BeatmapMetadata>();
Connection.DropTable<BeatmapDifficulty>();
Connection.DropTable<BeatmapSetInfo>();
Connection.DropTable<BeatmapSetFileInfo>();
Connection.DropTable<BeatmapInfo>();
}
Connection.CreateTable<BeatmapMetadata>();
Connection.CreateTable<BeatmapDifficulty>();
Connection.CreateTable<BeatmapSetInfo>();
Connection.CreateTable<BeatmapSetFileInfo>();
Connection.CreateTable<BeatmapInfo>();
}
protected override void StartupTasks()
{
base.StartupTasks();
cleanupPendingDeletions();
}
/// <summary>
/// Perform migrations between two store versions.
/// </summary>
/// <param name="currentVersion">The current store version. This will be zero on a fresh database initialisation.</param>
/// <param name="targetVersion">The target version which we are migrating to (equal to the current <see cref="StoreVersion"/>).</param>
protected override void PerformMigration(int currentVersion, int targetVersion)
{
base.PerformMigration(currentVersion, targetVersion);
while (currentVersion++ < targetVersion)
{
switch (currentVersion)
{
case 1:
case 2:
// cannot migrate; breaking underlying changes.
Reset();
break;
}
}
}
/// <summary>
/// Add a <see cref="BeatmapSetInfo"/> to the database.
/// </summary>
/// <param name="beatmapSet">The beatmap to add.</param>
public void Add(BeatmapSetInfo beatmapSet)
{
Connection.RunInTransaction(() =>
{
Connection.InsertOrReplaceWithChildren(beatmapSet, true);
});
BeatmapSetAdded?.Invoke(beatmapSet);
}
/// <summary>
/// Delete a <see cref="BeatmapSetInfo"/> to the database.
/// </summary>
/// <param name="beatmapSet">The beatmap to delete.</param>
/// <returns>Whether the beatmap's <see cref="BeatmapSetInfo.DeletePending"/> was changed.</returns>
public bool Delete(BeatmapSetInfo beatmapSet)
{
if (beatmapSet.DeletePending) return false;
beatmapSet.DeletePending = true;
Connection.Update(beatmapSet);
BeatmapSetRemoved?.Invoke(beatmapSet);
return true;
}
/// <summary>
/// Restore a previously deleted <see cref="BeatmapSetInfo"/>.
/// </summary>
/// <param name="beatmapSet">The beatmap to restore.</param>
/// <returns>Whether the beatmap's <see cref="BeatmapSetInfo.DeletePending"/> was changed.</returns>
public bool Undelete(BeatmapSetInfo beatmapSet)
{
if (!beatmapSet.DeletePending) return false;
beatmapSet.DeletePending = false;
Connection.Update(beatmapSet);
BeatmapSetAdded?.Invoke(beatmapSet);
return true;
}
private void cleanupPendingDeletions()
{
foreach (var b in QueryAndPopulate<BeatmapSetInfo>(b => b.DeletePending && !b.Protected))
{
try
{
// many-to-many join table entries are not automatically tidied.
Connection.Table<BeatmapSetFileInfo>().Delete(f => f.BeatmapSetInfoID == b.ID);
Connection.Delete(b, true);
}
catch (Exception e)
{
Logger.Error(e, $@"Could not delete beatmap {b}");
}
}
//this is required because sqlite migrations don't work, initially inserting nulls into this field.
//see https://github.com/praeclarum/sqlite-net/issues/326
Connection.Query<BeatmapSetInfo>("UPDATE BeatmapSetInfo SET DeletePending = 0 WHERE DeletePending IS NULL");
}
}
}

View File

@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.Linq;
using osu.Framework;
using osu.Framework.Graphics;
using osu.Game.Database;
namespace osu.Game.Beatmaps.Drawables
{
@ -59,10 +58,10 @@ namespace osu.Game.Beatmaps.Drawables
}
}
public BeatmapGroup(BeatmapSetInfo beatmapSet, BeatmapDatabase database)
public BeatmapGroup(BeatmapSetInfo beatmapSet, BeatmapManager manager)
{
BeatmapSet = beatmapSet;
WorkingBeatmap beatmap = database.GetWorkingBeatmap(BeatmapSet.Beatmaps.FirstOrDefault());
WorkingBeatmap beatmap = manager.GetWorkingBeatmap(BeatmapSet.Beatmaps.FirstOrDefault());
Header = new BeatmapSetHeader(beatmap)
{

View File

@ -6,7 +6,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.UserInterface;
@ -34,7 +33,7 @@ namespace osu.Game.Beatmaps.Drawables
GainedSelection?.Invoke(this);
background.ColourInfo = ColourInfo.GradientVertical(
background.Colour = ColourInfo.GradientVertical(
new Color4(20, 43, 51, 255),
new Color4(40, 86, 102, 255));

View File

@ -4,7 +4,6 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Database;
namespace osu.Game.Beatmaps.Drawables
{

View File

@ -35,7 +35,7 @@ namespace osu.Game.Beatmaps.Drawables
new PanelBackground(beatmap)
{
RelativeSizeAxes = Axes.Both,
OnLoadComplete = d => d.FadeInFromZero(400, EasingTypes.Out),
OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out),
}
)
{
@ -119,21 +119,21 @@ namespace osu.Game.Beatmaps.Drawables
new Box
{
RelativeSizeAxes = Axes.Both,
ColourInfo = ColourInfo.GradientHorizontal(
Colour = ColourInfo.GradientHorizontal(
Color4.Black, new Color4(0f, 0f, 0f, 0.9f)),
Width = 0.05f,
},
new Box
{
RelativeSizeAxes = Axes.Both,
ColourInfo = ColourInfo.GradientHorizontal(
Colour = ColourInfo.GradientHorizontal(
new Color4(0f, 0f, 0f, 0.9f), new Color4(0f, 0f, 0f, 0.1f)),
Width = 0.2f,
},
new Box
{
RelativeSizeAxes = Axes.Both,
ColourInfo = ColourInfo.GradientHorizontal(
Colour = ColourInfo.GradientHorizontal(
new Color4(0f, 0f, 0f, 0.1f), new Color4(0, 0, 0, 0)),
Width = 0.05f,
},

View File

@ -3,7 +3,6 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Game.Database;
using osu.Game.Graphics;
using OpenTK.Graphics;

View File

@ -3,7 +3,6 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Database;
using osu.Game.Graphics;
using OpenTK;
using OpenTK.Graphics;

View File

@ -64,9 +64,9 @@ namespace osu.Game.Beatmaps.Drawables
}
if (state == PanelSelectedState.Hidden)
FadeOut(300, EasingTypes.OutQuint);
this.FadeOut(300, Easing.OutQuint);
else
FadeIn(250);
this.FadeIn(250);
}
private PanelSelectedState state = PanelSelectedState.NotSelected;

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Textures;
using osu.Game.Database;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic;
using System.IO;
using osu.Game.Rulesets.Objects;
using osu.Game.Database;
namespace osu.Game.Beatmaps.Formats
{
@ -13,6 +12,11 @@ namespace osu.Game.Beatmaps.Formats
{
private static readonly Dictionary<string, Type> decoders = new Dictionary<string, Type>();
static BeatmapDecoder()
{
OsuLegacyDecoder.Register();
}
public static BeatmapDecoder GetDecoder(StreamReader stream)
{
string line = stream.ReadLine()?.Trim();

View File

@ -5,45 +5,11 @@ using System;
using System.Collections.Generic;
using System.IO;
using osu.Framework.IO.Stores;
using osu.Framework.Platform;
namespace osu.Game.Beatmaps.IO
{
public abstract class ArchiveReader : IDisposable, IResourceStore<byte[]>
{
private class Reader
{
public Func<Storage, string, bool> Test;
public Type Type;
}
private static readonly List<Reader> readers = new List<Reader>();
public static ArchiveReader GetReader(Storage storage, string path)
{
foreach (var reader in readers)
{
if (reader.Test(storage, path))
return (ArchiveReader)Activator.CreateInstance(reader.Type, storage.GetStream(path));
}
throw new IOException(@"Unknown file format");
}
protected static void AddReader<T>(Func<Storage, string, bool> test) where T : ArchiveReader
{
readers.Add(new Reader { Test = test, Type = typeof(T) });
}
/// <summary>
/// Gets a list of beatmap file names.
/// </summary>
public string[] BeatmapFilenames { get; protected set; }
/// <summary>
/// The storyboard filename. Null if no storyboard is present.
/// </summary>
public string StoryboardFilename { get; protected set; }
/// <summary>
/// Opens a stream for reading a specific file from this archive.
/// </summary>
@ -51,6 +17,8 @@ namespace osu.Game.Beatmaps.IO
public abstract void Dispose();
public abstract IEnumerable<string> Filenames { get; }
public virtual byte[] Get(string name)
{
using (Stream input = GetStream(name))

View File

@ -0,0 +1,33 @@
// Copyright (c) 2007-2017 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.IO;
using System.Linq;
namespace osu.Game.Beatmaps.IO
{
/// <summary>
/// Reads an extracted legacy beatmap from disk.
/// </summary>
public class LegacyFilesystemReader : ArchiveReader
{
private readonly string path;
public LegacyFilesystemReader(string path)
{
this.path = path;
}
public override Stream GetStream(string name) => File.OpenRead(Path.Combine(path, name));
public override void Dispose()
{
// no-op
}
public override IEnumerable<string> Filenames => Directory.GetFiles(path).Select(Path.GetFileName).ToArray();
public override Stream GetUnderlyingStream() => null;
}
}

View File

@ -1,25 +1,15 @@
// Copyright (c) 2007-2017 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.IO;
using System.Linq;
using Ionic.Zip;
using osu.Game.Beatmaps.Formats;
namespace osu.Game.Beatmaps.IO
{
public sealed class OszArchiveReader : ArchiveReader
{
public static void Register()
{
AddReader<OszArchiveReader>((storage, path) =>
{
using (var stream = storage.GetStream(path))
return stream != null && ZipFile.IsZipFile(stream, false);
});
OsuLegacyDecoder.Register();
}
private readonly Stream archiveStream;
private readonly ZipFile archive;
@ -27,13 +17,6 @@ namespace osu.Game.Beatmaps.IO
{
this.archiveStream = archiveStream;
archive = ZipFile.Read(archiveStream);
BeatmapFilenames = archive.Entries.Where(e => e.FileName.EndsWith(@".osu")).Select(e => e.FileName).ToArray();
if (BeatmapFilenames.Length == 0)
throw new FileNotFoundException(@"This directory contains no beatmaps");
StoryboardFilename = archive.Entries.Where(e => e.FileName.EndsWith(@".osb")).Select(e => e.FileName).FirstOrDefault();
}
public override Stream GetStream(string name)
@ -41,7 +24,16 @@ namespace osu.Game.Beatmaps.IO
ZipEntry entry = archive.Entries.SingleOrDefault(e => e.FileName == name);
if (entry == null)
throw new FileNotFoundException();
return entry.OpenReader();
// allow seeking
MemoryStream copy = new MemoryStream();
using (Stream s = entry.OpenReader())
s.CopyTo(copy);
copy.Position = 0;
return copy;
}
public override void Dispose()
@ -50,6 +42,8 @@ namespace osu.Game.Beatmaps.IO
archiveStream.Dispose();
}
public override IEnumerable<string> Filenames => archive.Entries.Select(e => e.FileName).ToArray();
public override Stream GetUnderlyingStream() => archiveStream;
}
}

View File

@ -3,7 +3,7 @@
using System.ComponentModel;
namespace osu.Game.Database
namespace osu.Game.Beatmaps
{
public enum RankStatus
{

View File

@ -4,7 +4,6 @@
using osu.Framework.Audio.Track;
using osu.Framework.Configuration;
using osu.Framework.Graphics.Textures;
using osu.Game.Database;
using osu.Game.Rulesets.Mods;
using System;
using System.Collections.Generic;
@ -22,14 +21,11 @@ namespace osu.Game.Beatmaps
public readonly Bindable<IEnumerable<Mod>> Mods = new Bindable<IEnumerable<Mod>>(new Mod[] { });
public readonly bool WithStoryboard;
protected WorkingBeatmap(BeatmapInfo beatmapInfo, bool withStoryboard = false)
protected WorkingBeatmap(BeatmapInfo beatmapInfo)
{
BeatmapInfo = beatmapInfo;
BeatmapSetInfo = beatmapInfo.BeatmapSet;
Metadata = beatmapInfo.Metadata ?? BeatmapSetInfo.Metadata;
WithStoryboard = withStoryboard;
Mods.ValueChanged += mods => applyRateAdjustments();
}

View File

@ -1,303 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using osu.Framework.Extensions;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.IO;
using osu.Game.IPC;
using osu.Game.Screens.Menu;
using SQLite.Net;
using SQLiteNetExtensions.Extensions;
namespace osu.Game.Database
{
public class BeatmapDatabase : Database
{
private readonly RulesetDatabase rulesets;
public event Action<BeatmapSetInfo> BeatmapSetAdded;
public event Action<BeatmapSetInfo> BeatmapSetRemoved;
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
private BeatmapIPCChannel ipc;
/// <summary>
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
/// </summary>
public WorkingBeatmap DefaultBeatmap { private get; set; }
public BeatmapDatabase(Storage storage, SQLiteConnection connection, RulesetDatabase rulesets, IIpcHost importHost = null) : base(storage, connection)
{
this.rulesets = rulesets;
if (importHost != null)
ipc = new BeatmapIPCChannel(importHost, this);
}
private void deletePending()
{
foreach (var b in GetAllWithChildren<BeatmapSetInfo>(b => b.DeletePending))
{
if (b.Hash == Intro.MENU_MUSIC_BEATMAP_HASH)
// this is a bit hacky, but will do for now.
continue;
try
{
Storage.Delete(b.Path);
foreach (var i in b.Beatmaps)
{
if (i.Metadata != null) Connection.Delete(i.Metadata);
if (i.Difficulty != null) Connection.Delete(i.Difficulty);
Connection.Delete(i);
}
if (b.Metadata != null) Connection.Delete(b.Metadata);
Connection.Delete(b);
}
catch (Exception e)
{
Logger.Error(e, $@"Could not delete beatmap {b}");
}
}
//this is required because sqlite migrations don't work, initially inserting nulls into this field.
//see https://github.com/praeclarum/sqlite-net/issues/326
Connection.Query<BeatmapSetInfo>("UPDATE BeatmapSetInfo SET DeletePending = 0 WHERE DeletePending IS NULL");
}
protected override void Prepare(bool reset = false)
{
Connection.CreateTable<BeatmapMetadata>();
Connection.CreateTable<BeatmapDifficulty>();
Connection.CreateTable<BeatmapSetInfo>();
Connection.CreateTable<BeatmapInfo>();
if (reset)
{
Storage.DeleteDatabase(@"beatmaps");
foreach (var setInfo in Query<BeatmapSetInfo>())
{
if (Storage.Exists(setInfo.Path))
Storage.Delete(setInfo.Path);
}
Connection.DeleteAll<BeatmapMetadata>();
Connection.DeleteAll<BeatmapDifficulty>();
Connection.DeleteAll<BeatmapSetInfo>();
Connection.DeleteAll<BeatmapInfo>();
}
deletePending();
}
protected override Type[] ValidTypes => new[] {
typeof(BeatmapSetInfo),
typeof(BeatmapInfo),
typeof(BeatmapMetadata),
typeof(BeatmapDifficulty),
};
public void Import(string path)
{
try
{
Import(ArchiveReader.GetReader(Storage, path));
// We may or may not want to delete the file depending on where it is stored.
// e.g. reconstructing/repairing database with beatmaps from default storage.
// Also, not always a single file, i.e. for LegacyFilesystemReader
// TODO: Add a check to prevent files from storage to be deleted.
try
{
File.Delete(path);
}
catch (Exception e)
{
Logger.Error(e, $@"Could not delete file at {path}");
}
}
catch (Exception e)
{
e = e.InnerException ?? e;
Logger.Error(e, @"Could not import beatmap set");
}
}
public void Import(ArchiveReader archiveReader)
{
BeatmapSetInfo set = getBeatmapSet(archiveReader);
//If we have an ID then we already exist in the database.
if (set.ID == 0)
Import(new[] { set });
}
/// <summary>
/// Import multiple <see cref="BeatmapSetInfo"/> from <paramref name="paths"/>.
/// </summary>
/// <param name="paths">Multiple locations on disk</param>
public void Import(params string[] paths)
{
foreach (string p in paths)
{
//In case the file was imported twice and deleted after the first time
if (File.Exists(p))
Import(p);
}
}
/// <summary>
/// Duplicates content from <paramref name="path"/> to storage and returns a representing <see cref="BeatmapSetInfo"/>.
/// </summary>
/// <param name="path">Content location</param>
/// <returns><see cref="BeatmapSetInfo"/></returns>
private BeatmapSetInfo getBeatmapSet(string path) => getBeatmapSet(ArchiveReader.GetReader(Storage, path));
private BeatmapSetInfo getBeatmapSet(ArchiveReader archiveReader)
{
BeatmapMetadata metadata;
using (var stream = new StreamReader(archiveReader.GetStream(archiveReader.BeatmapFilenames[0])))
metadata = BeatmapDecoder.GetDecoder(stream).Decode(stream).Metadata;
string hash;
string path;
using (var input = archiveReader.GetUnderlyingStream())
{
hash = input.GetMd5Hash();
input.Seek(0, SeekOrigin.Begin);
path = Path.Combine(@"beatmaps", hash.Remove(1), hash.Remove(2), hash);
if (!Storage.Exists(path))
using (var output = Storage.GetStream(path, FileAccess.Write))
input.CopyTo(output);
}
var existing = Connection.Table<BeatmapSetInfo>().FirstOrDefault(b => b.Hash == hash);
if (existing != null)
{
GetChildren(existing);
if (existing.DeletePending)
{
existing.DeletePending = false;
Update(existing, false);
BeatmapSetAdded?.Invoke(existing);
}
return existing;
}
var beatmapSet = new BeatmapSetInfo
{
OnlineBeatmapSetID = metadata.OnlineBeatmapSetID,
Beatmaps = new List<BeatmapInfo>(),
Path = path,
Hash = hash,
Metadata = metadata
};
using (var archive = ArchiveReader.GetReader(Storage, path))
{
string[] mapNames = archive.BeatmapFilenames;
foreach (var name in mapNames)
using (var raw = archive.GetStream(name))
using (var ms = new MemoryStream()) //we need a memory stream so we can seek and shit
using (var sr = new StreamReader(ms))
{
raw.CopyTo(ms);
ms.Position = 0;
var decoder = BeatmapDecoder.GetDecoder(sr);
Beatmap beatmap = decoder.Decode(sr);
beatmap.BeatmapInfo.Path = name;
beatmap.BeatmapInfo.Hash = ms.GetMd5Hash();
// TODO: Diff beatmap metadata with set metadata and leave it here if necessary
beatmap.BeatmapInfo.Metadata = null;
// TODO: this should be done in a better place once we actually need to dynamically update it.
beatmap.BeatmapInfo.Ruleset = rulesets.Query<RulesetInfo>().FirstOrDefault(r => r.ID == beatmap.BeatmapInfo.RulesetID);
beatmap.BeatmapInfo.StarDifficulty = rulesets.Query<RulesetInfo>().FirstOrDefault(r => r.ID == beatmap.BeatmapInfo.RulesetID)?.CreateInstance()?.CreateDifficultyCalculator(beatmap).Calculate() ?? 0;
beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo);
}
beatmapSet.StoryboardFile = archive.StoryboardFilename;
}
return beatmapSet;
}
public void Import(IEnumerable<BeatmapSetInfo> beatmapSets)
{
lock (Connection)
{
Connection.BeginTransaction();
foreach (var s in beatmapSets)
{
Connection.InsertOrReplaceWithChildren(s, true);
BeatmapSetAdded?.Invoke(s);
}
Connection.Commit();
}
}
public void Delete(BeatmapSetInfo beatmapSet)
{
beatmapSet.DeletePending = true;
Update(beatmapSet, false);
BeatmapSetRemoved?.Invoke(beatmapSet);
}
public ArchiveReader GetReader(BeatmapSetInfo beatmapSet)
{
if (string.IsNullOrEmpty(beatmapSet.Path))
return null;
return ArchiveReader.GetReader(Storage, beatmapSet.Path);
}
public BeatmapSetInfo GetBeatmapSet(int id)
{
return Query<BeatmapSetInfo>().FirstOrDefault(s => s.OnlineBeatmapSetID == id);
}
public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null, bool withStoryboard = false)
{
if (beatmapInfo == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo)
return DefaultBeatmap;
if (beatmapInfo.BeatmapSet == null || beatmapInfo.Ruleset == null)
beatmapInfo = GetChildren(beatmapInfo, true);
if (beatmapInfo.BeatmapSet == null)
throw new InvalidOperationException($@"Beatmap set {beatmapInfo.BeatmapSetInfoID} is not in the local database.");
if (beatmapInfo.Metadata == null)
beatmapInfo.Metadata = beatmapInfo.BeatmapSet.Metadata;
WorkingBeatmap working = new DatabaseWorkingBeatmap(this, beatmapInfo, withStoryboard);
previous?.TransferTo(working);
return working;
}
public bool Exists(BeatmapSetInfo beatmapSet) => Storage.Exists(beatmapSet.Path);
}
}

View File

@ -1,80 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using osu.Framework.Logging;
using osu.Framework.Platform;
using SQLite.Net;
using SQLiteNetExtensions.Extensions;
namespace osu.Game.Database
{
public abstract class Database
{
protected SQLiteConnection Connection { get; }
protected Storage Storage { get; }
protected Database(Storage storage, SQLiteConnection connection)
{
Storage = storage;
Connection = connection;
try
{
Prepare();
}
catch (Exception e)
{
Logger.Error(e, $@"Failed to initialise the {GetType()}! Trying again with a clean database...");
Prepare(true);
}
}
/// <summary>
/// Prepare this database for use.
/// </summary>
protected abstract void Prepare(bool reset = false);
/// <summary>
/// Reset this database to a default state. Undo all changes to database and storage backings.
/// </summary>
public void Reset() => Prepare(true);
public TableQuery<T> Query<T>() where T : class
{
return Connection.Table<T>();
}
/// <summary>
/// This is expensive. Use with caution.
/// </summary>
public List<T> GetAllWithChildren<T>(Expression<Func<T, bool>> filter = null, bool recursive = true)
where T : class
{
return Connection.GetAllWithChildren(filter, recursive);
}
public T GetChildren<T>(T item, bool recursive = false)
{
if (item == null) return default(T);
Connection.GetChildren(item, recursive);
return item;
}
protected abstract Type[] ValidTypes { get; }
public void Update<T>(T record, bool cascade = true) where T : class
{
if (ValidTypes.All(t => t != typeof(T)))
throw new ArgumentException("Must be a type managed by BeatmapDatabase", nameof(T));
if (cascade)
Connection.UpdateWithChildren(record);
else
Connection.Update(record);
}
}
}

View File

@ -0,0 +1,131 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using osu.Framework.Logging;
using osu.Framework.Platform;
using SQLite.Net;
using SQLiteNetExtensions.Extensions;
namespace osu.Game.Database
{
public abstract class DatabaseBackedStore
{
protected readonly Storage Storage;
protected readonly SQLiteConnection Connection;
protected virtual int StoreVersion => 1;
protected DatabaseBackedStore(SQLiteConnection connection, Storage storage = null)
{
Storage = storage;
Connection = connection;
try
{
Prepare();
}
catch (Exception e)
{
Logger.Error(e, $@"Failed to initialise the {GetType()}! Trying again with a clean database...");
Prepare(true);
}
checkMigrations();
}
private void checkMigrations()
{
var storeName = GetType().Name;
var reportedVersion = Connection.Table<StoreVersion>().FirstOrDefault(s => s.StoreName == storeName) ?? new StoreVersion
{
StoreName = storeName,
Version = 0
};
if (reportedVersion.Version != StoreVersion)
PerformMigration(reportedVersion.Version, reportedVersion.Version = StoreVersion);
Connection.InsertOrReplace(reportedVersion);
StartupTasks();
}
/// <summary>
/// Called when the database version of this store doesn't match the local version.
/// Any manual migration operations should be performed in this.
/// </summary>
/// <param name="currentVersion">The current store version. This will be zero on a fresh database initialisation.</param>
/// <param name="targetVersion">The target version which we are migrating to (equal to the current <see cref="StoreVersion"/>).</param>
protected virtual void PerformMigration(int currentVersion, int targetVersion)
{
}
/// <summary>
/// Perform any common startup tasks. Runs after <see cref="Prepare(bool)"/> and <see cref="PerformMigration(int, int)"/>.
/// </summary>
protected virtual void StartupTasks()
{
}
/// <summary>
/// Prepare this database for use. Tables should be created here.
/// </summary>
protected abstract void Prepare(bool reset = false);
/// <summary>
/// Reset this database to a default state. Undo all changes to database and storage backings.
/// </summary>
public void Reset() => Prepare(true);
public TableQuery<T> Query<T>(Expression<Func<T, bool>> filter = null) where T : class
{
checkType(typeof(T));
var query = Connection.Table<T>();
if (filter != null)
query = query.Where(filter);
return query;
}
/// <summary>
/// Query and populate results.
/// </summary>
/// <param name="filter">An filter to refine results.</param>
/// <returns></returns>
public List<T> QueryAndPopulate<T>(Expression<Func<T, bool>> filter)
where T : class
{
checkType(typeof(T));
return Connection.GetAllWithChildren(filter, true);
}
/// <summary>
/// Populate a database-backed item.
/// </summary>
/// <param name="item"></param>
/// <param name="recursive">Whether population should recurse beyond a single level.</param>
public void Populate<T>(T item, bool recursive = true)
{
checkType(item.GetType());
Connection.GetChildren(item, recursive);
}
private void checkType(Type type)
{
if (!ValidTypes.Contains(type))
throw new InvalidOperationException($"The requested operation specified a type of {type}, which is invalid for this {nameof(DatabaseBackedStore)}.");
}
protected abstract Type[] ValidTypes { get; }
}
}

View File

@ -1,75 +0,0 @@
// Copyright (c) 2007-2017 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.Audio.Track;
using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.IO;
namespace osu.Game.Database
{
internal class DatabaseWorkingBeatmap : WorkingBeatmap
{
private readonly BeatmapDatabase database;
public DatabaseWorkingBeatmap(BeatmapDatabase database, BeatmapInfo beatmapInfo, bool withStoryboard = false)
: base(beatmapInfo, withStoryboard)
{
this.database = database;
}
private ArchiveReader getReader() => database?.GetReader(BeatmapSetInfo);
protected override Beatmap GetBeatmap()
{
try
{
Beatmap beatmap;
using (var reader = getReader())
{
BeatmapDecoder decoder;
using (var stream = new StreamReader(reader.GetStream(BeatmapInfo.Path)))
{
decoder = BeatmapDecoder.GetDecoder(stream);
beatmap = decoder.Decode(stream);
}
if (beatmap == null || !WithStoryboard || BeatmapSetInfo.StoryboardFile == null)
return beatmap;
using (var stream = new StreamReader(reader.GetStream(BeatmapSetInfo.StoryboardFile)))
decoder.Decode(stream, beatmap);
}
return beatmap;
}
catch { return null; }
}
protected override Texture GetBackground()
{
if (Metadata?.BackgroundFile == null)
return null;
try
{
using (var reader = getReader())
return new TextureStore(new RawTextureLoaderStore(reader), false).Get(Metadata.BackgroundFile);
}
catch { return null; }
}
protected override Track GetTrack()
{
try
{
var trackData = getReader()?.GetStream(Metadata.AudioFile);
return trackData == null ? null : new TrackBass(trackData);
}
catch { return new TrackVirtual(); }
}
}
}

View File

@ -0,0 +1,15 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using SQLite.Net.Attributes;
namespace osu.Game.Database
{
public class StoreVersion
{
[PrimaryKey]
public string StoreName { get; set; }
public int Version { get; set; }
}
}

View File

@ -42,7 +42,7 @@ namespace osu.Game.Graphics.Containers
{
if (!parallaxEnabled)
{
content.MoveTo(Vector2.Zero, firstUpdate ? 0 : 1000, EasingTypes.OutQuint);
content.MoveTo(Vector2.Zero, firstUpdate ? 0 : 1000, Easing.OutQuint);
content.Scale = new Vector2(1 + ParallaxAmount);
}
};
@ -57,7 +57,7 @@ namespace osu.Game.Graphics.Containers
if (parallaxEnabled)
{
Vector2 offset = input.CurrentState.Mouse == null ? Vector2.Zero : ToLocalSpace(input.CurrentState.Mouse.NativeState.Position) - DrawSize / 2;
content.MoveTo(offset * ParallaxAmount, firstUpdate ? 0 : 1000, EasingTypes.OutQuint);
content.MoveTo(offset * ParallaxAmount, firstUpdate ? 0 : 1000, Easing.OutQuint);
content.Scale = new Vector2(1 + ParallaxAmount);
}

View File

@ -13,7 +13,6 @@ using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Database;
namespace osu.Game.Graphics.Cursor
{
@ -29,14 +28,14 @@ namespace osu.Game.Graphics.Cursor
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
ActiveCursor.Scale = new Vector2(1);
ActiveCursor.ScaleTo(1.2f, 100, EasingTypes.OutQuad);
ActiveCursor.ScaleTo(1.2f, 100, Easing.OutQuad);
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
if (!state.Mouse.HasMainButtonPressed)
ActiveCursor.ScaleTo(1, 200, EasingTypes.OutQuad);
ActiveCursor.ScaleTo(1, 200, Easing.OutQuad);
return base.OnMouseUp(state, args);
}

View File

@ -34,7 +34,7 @@ namespace osu.Game.Graphics.Cursor
if (diff > 180) diff -= 360;
degrees = ActiveCursor.Rotation + diff;
ActiveCursor.RotateTo(degrees, 600, EasingTypes.OutQuint);
ActiveCursor.RotateTo(degrees, 600, Easing.OutQuint);
}
return base.OnMouseMove(state);
@ -49,10 +49,10 @@ namespace osu.Game.Graphics.Cursor
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
ActiveCursor.Scale = new Vector2(1);
ActiveCursor.ScaleTo(0.90f, 800, EasingTypes.OutQuint);
ActiveCursor.ScaleTo(0.90f, 800, Easing.OutQuint);
((Cursor)ActiveCursor).AdditiveLayer.Alpha = 0;
((Cursor)ActiveCursor).AdditiveLayer.FadeInFromZero(800, EasingTypes.OutQuint);
((Cursor)ActiveCursor).AdditiveLayer.FadeInFromZero(800, Easing.OutQuint);
return base.OnMouseDown(state, args);
}
@ -62,9 +62,9 @@ namespace osu.Game.Graphics.Cursor
{
dragging = false;
((Cursor)ActiveCursor).AdditiveLayer.FadeOut(500, EasingTypes.OutQuint);
ActiveCursor.RotateTo(0, 600 * (1 + Math.Abs(ActiveCursor.Rotation / 720)), EasingTypes.OutElasticHalf);
ActiveCursor.ScaleTo(1, 500, EasingTypes.OutElastic);
((Cursor)ActiveCursor).AdditiveLayer.FadeOut(500, Easing.OutQuint);
ActiveCursor.RotateTo(0, 600 * (1 + Math.Abs(ActiveCursor.Rotation / 720)), Easing.OutElasticHalf);
ActiveCursor.ScaleTo(1, 500, Easing.OutElastic);
}
return base.OnMouseUp(state, args);
@ -72,21 +72,21 @@ namespace osu.Game.Graphics.Cursor
protected override bool OnClick(InputState state)
{
((Cursor)ActiveCursor).AdditiveLayer.FadeOutFromOne(500, EasingTypes.OutQuint);
((Cursor)ActiveCursor).AdditiveLayer.FadeOutFromOne(500, Easing.OutQuint);
return base.OnClick(state);
}
protected override void PopIn()
{
ActiveCursor.FadeTo(1, 250, EasingTypes.OutQuint);
ActiveCursor.ScaleTo(1, 400, EasingTypes.OutQuint);
ActiveCursor.FadeTo(1, 250, Easing.OutQuint);
ActiveCursor.ScaleTo(1, 400, Easing.OutQuint);
}
protected override void PopOut()
{
ActiveCursor.FadeTo(0, 900, EasingTypes.OutQuint);
ActiveCursor.ScaleTo(0, 500, EasingTypes.In);
ActiveCursor.FadeTo(0, 900, Easing.OutQuint);
ActiveCursor.ScaleTo(0, 500, Easing.In);
}
public class Cursor : Container

View File

@ -37,7 +37,7 @@ namespace osu.Game.Graphics.Cursor
if (IsPresent)
{
AutoSizeDuration = 250;
background.FlashColour(OsuColour.Gray(0.4f), 1000, EasingTypes.OutQuint);
background.FlashColour(OsuColour.Gray(0.4f), 1000, Easing.OutQuint);
}
else
AutoSizeDuration = 0;
@ -48,7 +48,7 @@ namespace osu.Game.Graphics.Cursor
public OsuTooltip()
{
AutoSizeEasing = EasingTypes.OutQuint;
AutoSizeEasing = Easing.OutQuint;
CornerRadius = 5;
Masking = true;
@ -83,16 +83,10 @@ namespace osu.Game.Graphics.Cursor
protected override void PopIn()
{
instantMovement |= !IsPresent;
ClearTransforms();
FadeIn(500, EasingTypes.OutQuint);
this.FadeIn(500, Easing.OutQuint);
}
protected override void PopOut()
{
using (BeginDelayedSequence(150))
FadeOut(500, EasingTypes.OutQuint);
}
protected override void PopOut() => this.Delay(150).FadeOut(500, Easing.OutQuint);
public override void Move(Vector2 pos)
{
@ -103,7 +97,7 @@ namespace osu.Game.Graphics.Cursor
}
else
{
MoveTo(pos, 200, EasingTypes.OutQuint);
this.MoveTo(pos, 200, Easing.OutQuint);
}
}
}

View File

@ -4,7 +4,6 @@
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Transforms;
using osu.Game.Graphics.Transforms;
namespace osu.Game.Graphics
{
@ -27,10 +26,8 @@ namespace osu.Game.Graphics
/// <param name="newColour">The new accent colour.</param>
/// <param name="duration">The tween duration.</param>
/// <param name="easing">The tween easing.</param>
public static void FadeAccent<T>(this T accentedDrawable, Color4 newColour, double duration = 0, EasingTypes easing = EasingTypes.None)
where T : Transformable<Drawable>, IHasAccentColour
{
accentedDrawable.TransformTo(newColour, duration, easing, new TransformAccent());
}
public static TransformSequence<T> FadeAccent<T>(this T accentedDrawable, Color4 newColour, double duration = 0, Easing easing = Easing.None)
where T : IHasAccentColour
=> accentedDrawable.TransformTo(nameof(accentedDrawable.AccentColour), newColour, duration, easing);
}
}

View File

@ -13,6 +13,9 @@ namespace osu.Game.Graphics
public static Color4 FromHex(string hex)
{
if (hex[0] == '#')
hex = hex.Substring(1);
switch (hex.Length)
{
default:

View File

@ -1,31 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Transforms;
using osu.Framework.MathUtils;
namespace osu.Game.Graphics.Transforms
{
public class TransformAccent : Transform<Color4, Drawable>
{
/// <summary>
/// Current value of the transformed colour in linear colour space.
/// </summary>
public virtual Color4 CurrentValue
{
get
{
double time = Time?.Current ?? 0;
if (time < StartTime) return StartValue;
if (time >= EndTime) return EndValue;
return Interpolation.ValueAt(time, StartValue, EndValue, StartTime, EndTime, Easing);
}
}
public override void Apply(Drawable d) => ((IHasAccentColour)d).AccentColour = CurrentValue;
public override void ReadIntoStartValue(Drawable d) => StartValue = ((IHasAccentColour)d).AccentColour;
}
}

View File

@ -17,7 +17,7 @@ namespace osu.Game.Graphics.UserInterface
private const int resize_duration = 250;
private const EasingTypes easing = EasingTypes.InOutCubic;
private const Easing easing = Easing.InOutCubic;
private float length;
/// <summary>

View File

@ -28,7 +28,7 @@ namespace osu.Game.Graphics.UserInterface
var tabIndex = TabContainer.IndexOf(TabMap[tab]);
t.State = tIndex < tabIndex ? Visibility.Hidden : Visibility.Visible;
t.Chevron.FadeTo(tIndex <= tabIndex ? 0f : 1f, 500, EasingTypes.OutQuint);
t.Chevron.FadeTo(tIndex <= tabIndex ? 0f : 1f, 500, Easing.OutQuint);
}
};
}
@ -54,13 +54,13 @@ namespace osu.Game.Graphics.UserInterface
if (State == Visibility.Visible)
{
FadeIn(transition_duration, EasingTypes.OutQuint);
ScaleTo(new Vector2(1f), transition_duration, EasingTypes.OutQuint);
this.FadeIn(transition_duration, Easing.OutQuint);
this.ScaleTo(new Vector2(1f), transition_duration, Easing.OutQuint);
}
else
{
FadeOut(transition_duration, EasingTypes.OutQuint);
ScaleTo(new Vector2(0.8f, 1f), transition_duration, EasingTypes.OutQuint);
this.FadeOut(transition_duration, Easing.OutQuint);
this.ScaleTo(new Vector2(0.8f, 1f), transition_duration, Easing.OutQuint);
}
}
}

View File

@ -96,11 +96,10 @@ namespace osu.Game.Graphics.UserInterface
protected override bool OnClick(Framework.Input.InputState state)
{
didClick = true;
colourContainer.ResizeTo(new Vector2(1.5f, 1f), click_duration, EasingTypes.In);
colourContainer.ResizeTo(new Vector2(1.5f, 1f), click_duration, Easing.In);
flash();
Delay(click_duration);
Schedule(delegate {
this.Delay(click_duration).Schedule(delegate {
colourContainer.ResizeTo(new Vector2(0.8f, 1f));
spriteText.Spacing = Vector2.Zero;
glowContainer.FadeOut();
@ -111,10 +110,10 @@ namespace osu.Game.Graphics.UserInterface
protected override bool OnHover(Framework.Input.InputState state)
{
spriteText.TransformSpacingTo(hoverSpacing, hover_duration, EasingTypes.OutElastic);
spriteText.TransformSpacingTo(hoverSpacing, hover_duration, Easing.OutElastic);
colourContainer.ResizeTo(new Vector2(hover_width, 1f), hover_duration, EasingTypes.OutElastic);
glowContainer.FadeIn(glow_fade_duration, EasingTypes.Out);
colourContainer.ResizeTo(new Vector2(hover_width, 1f), hover_duration, Easing.OutElastic);
glowContainer.FadeIn(glow_fade_duration, Easing.Out);
base.OnHover(state);
return true;
}
@ -123,9 +122,9 @@ namespace osu.Game.Graphics.UserInterface
{
if (!didClick)
{
colourContainer.ResizeTo(new Vector2(0.8f, 1f), hover_duration, EasingTypes.OutElastic);
spriteText.TransformSpacingTo(Vector2.Zero, hover_duration, EasingTypes.OutElastic);
glowContainer.FadeOut(glow_fade_duration, EasingTypes.Out);
colourContainer.ResizeTo(new Vector2(0.8f, 1f), hover_duration, Easing.OutElastic);
spriteText.TransformSpacingTo(Vector2.Zero, hover_duration, Easing.OutElastic);
glowContainer.FadeOut(glow_fade_duration, Easing.Out);
}
didClick = false;
@ -149,9 +148,9 @@ namespace osu.Game.Graphics.UserInterface
private void updateGlow()
{
leftGlow.ColourInfo = ColourInfo.GradientHorizontal(new Color4(ButtonColour.R, ButtonColour.G, ButtonColour.B, 0f), ButtonColour);
leftGlow.Colour = ColourInfo.GradientHorizontal(new Color4(ButtonColour.R, ButtonColour.G, ButtonColour.B, 0f), ButtonColour);
centerGlow.Colour = ButtonColour;
rightGlow.ColourInfo = ColourInfo.GradientHorizontal(ButtonColour, new Color4(ButtonColour.R, ButtonColour.G, ButtonColour.B, 0f));
rightGlow.Colour = ColourInfo.GradientHorizontal(ButtonColour, new Color4(ButtonColour.R, ButtonColour.G, ButtonColour.B, 0f));
}
public DialogButton()

View File

@ -86,31 +86,31 @@ namespace osu.Game.Graphics.UserInterface
protected override bool OnHover(InputState state)
{
hover.FadeIn(500, EasingTypes.OutQuint);
hover.FadeIn(500, Easing.OutQuint);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
hover.FadeOut(500, EasingTypes.OutQuint);
hover.FadeOut(500, Easing.OutQuint);
base.OnHoverLost(state);
}
protected override bool OnClick(InputState state)
{
hover.FlashColour(flashColour, 800, EasingTypes.OutQuint);
hover.FlashColour(flashColour, 800, Easing.OutQuint);
return base.OnClick(state);
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
content.ScaleTo(0.75f, 2000, EasingTypes.OutQuint);
content.ScaleTo(0.75f, 2000, Easing.OutQuint);
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
content.ScaleTo(1, 1000, EasingTypes.OutElastic);
content.ScaleTo(1, 1000, Easing.OutElastic);
return base.OnMouseUp(state, args);
}
}

View File

@ -49,7 +49,7 @@ namespace osu.Game.Graphics.UserInterface
values = value.ToArray();
applyPath();
maskingContainer.Width = 0;
maskingContainer.ResizeWidthTo(1, transform_duration, EasingTypes.OutQuint);
maskingContainer.ResizeWidthTo(1, transform_duration, Easing.OutQuint);
}
}

View File

@ -34,14 +34,13 @@ namespace osu.Game.Graphics.UserInterface
{
base.LoadComplete();
using (spinner.BeginLoopedSequence())
spinner.RotateTo(360, 2000);
spinner.Spin(2000, RotationDirection.Clockwise);
}
private const float transition_duration = 500;
protected override void PopIn() => FadeIn(transition_duration * 5, EasingTypes.OutQuint);
protected override void PopIn() => this.FadeIn(transition_duration * 5, Easing.OutQuint);
protected override void PopOut() => FadeOut(transition_duration, EasingTypes.OutQuint);
protected override void PopOut() => this.FadeOut(transition_duration, Easing.OutQuint);
}
}

View File

@ -43,9 +43,9 @@ namespace osu.Game.Graphics.UserInterface
Current.ValueChanged += newValue =>
{
if (newValue)
fill.FadeIn(200, EasingTypes.OutQuint);
fill.FadeIn(200, Easing.OutQuint);
else
fill.FadeTo(0.01f, 200, EasingTypes.OutQuint); //todo: remove once we figure why containers aren't drawing at all times
fill.FadeTo(0.01f, 200, Easing.OutQuint); //todo: remove once we figure why containers aren't drawing at all times
};
}
@ -80,13 +80,13 @@ namespace osu.Game.Graphics.UserInterface
if (value)
{
FadeColour(GlowingAccentColour, 500, EasingTypes.OutQuint);
FadeEdgeEffectTo(1, 500, EasingTypes.OutQuint);
this.FadeColour(GlowingAccentColour, 500, Easing.OutQuint);
FadeEdgeEffectTo(1, 500, Easing.OutQuint);
}
else
{
FadeEdgeEffectTo(0, 500);
FadeColour(AccentColour, 500);
this.FadeColour(AccentColour, 500);
}
}
}
@ -95,7 +95,7 @@ namespace osu.Game.Graphics.UserInterface
{
set
{
ResizeTo(new Vector2(value ? EXPANDED_SIZE : COLLAPSED_SIZE, 12), 500, EasingTypes.OutQuint);
this.ResizeTo(new Vector2(value ? EXPANDED_SIZE : COLLAPSED_SIZE, 12), 500, Easing.OutQuint);
}
}

View File

@ -68,6 +68,14 @@ namespace osu.Game.Graphics.UserInterface
sampleClick = audio.Sample.Get(@"UI/generic-click");
sampleHover = audio.Sample.Get(@"UI/generic-hover");
Enabled.ValueChanged += enabled_ValueChanged;
Enabled.TriggerChange();
}
private void enabled_ValueChanged(bool enabled)
{
this.FadeColour(enabled ? Color4.White : Color4.Gray, 200, Easing.OutQuint);
}
protected override bool OnClick(InputState state)
@ -91,13 +99,13 @@ namespace osu.Game.Graphics.UserInterface
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
Content.ScaleTo(0.9f, 4000, EasingTypes.OutQuint);
Content.ScaleTo(0.9f, 4000, Easing.OutQuint);
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
Content.ScaleTo(1, 1000, EasingTypes.OutElastic);
Content.ScaleTo(1, 1000, Easing.OutElastic);
return base.OnMouseUp(state, args);
}
}

View File

@ -39,13 +39,13 @@ namespace osu.Game.Graphics.UserInterface
Background.Colour = colours.ContextMenuGray;
}
protected override void AnimateOpen() => FadeIn(fade_duration, EasingTypes.OutQuint);
protected override void AnimateClose() => FadeOut(fade_duration, EasingTypes.OutQuint);
protected override void AnimateOpen() => this.FadeIn(fade_duration, Easing.OutQuint);
protected override void AnimateClose() => this.FadeOut(fade_duration, Easing.OutQuint);
protected override void UpdateContentHeight()
{
var actualHeight = (RelativeSizeAxes & Axes.Y) > 0 ? 1 : ContentHeight;
ResizeTo(new Vector2(1, State == MenuState.Opened ? actualHeight : 0), 300, EasingTypes.OutQuint);
this.ResizeTo(new Vector2(1, State == MenuState.Opened ? actualHeight : 0), 300, Easing.OutQuint);
}
}
}

View File

@ -93,15 +93,15 @@ namespace osu.Game.Graphics.UserInterface
protected override bool OnHover(InputState state)
{
sampleHover.Play();
textBold.FadeIn(transition_length, EasingTypes.OutQuint);
text.FadeOut(transition_length, EasingTypes.OutQuint);
textBold.FadeIn(transition_length, Easing.OutQuint);
text.FadeOut(transition_length, Easing.OutQuint);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
textBold.FadeOut(transition_length, EasingTypes.OutQuint);
text.FadeIn(transition_length, EasingTypes.OutQuint);
textBold.FadeOut(transition_length, Easing.OutQuint);
text.FadeIn(transition_length, Easing.OutQuint);
base.OnHoverLost(state);
}

View File

@ -19,14 +19,14 @@ namespace osu.Game.Graphics.UserInterface
ItemsContainer.Padding = new MarginPadding(5);
}
protected override void AnimateOpen() => FadeIn(300, EasingTypes.OutQuint);
protected override void AnimateOpen() => this.FadeIn(300, Easing.OutQuint);
protected override void AnimateClose() => FadeOut(300, EasingTypes.OutQuint);
protected override void AnimateClose() => this.FadeOut(300, Easing.OutQuint);
protected override void UpdateContentHeight()
{
var actualHeight = (RelativeSizeAxes & Axes.Y) > 0 ? 1 : ContentHeight;
ResizeTo(new Vector2(1, State == MenuState.Opened ? actualHeight : 0), 300, EasingTypes.OutQuint);
this.ResizeTo(new Vector2(1, State == MenuState.Opened ? actualHeight : 0), 300, Easing.OutQuint);
}
}
}

View File

@ -47,8 +47,8 @@ namespace osu.Game.Graphics.UserInterface
protected override void LoadComplete()
{
base.LoadComplete();
circle.FadeIn(500, EasingTypes.OutQuint);
circle.ResizeTo(new Vector2(0.8f), 500, EasingTypes.OutQuint);
circle.FadeIn(500, Easing.OutQuint);
circle.ResizeTo(new Vector2(0.8f), 500, Easing.OutQuint);
}
}
}

View File

@ -166,7 +166,7 @@ namespace osu.Game.Graphics.UserInterface
protected override void UpdateValue(float value)
{
Nub.MoveToX(RangePadding + UsableWidth * value, 250, EasingTypes.OutQuint);
Nub.MoveToX(RangePadding + UsableWidth * value, 250, Easing.OutQuint);
}
}
}

View File

@ -77,14 +77,14 @@ namespace osu.Game.Graphics.UserInterface
private void fadeActive()
{
box.FadeIn(transition_length, EasingTypes.OutQuint);
Text.FadeColour(Color4.White, transition_length, EasingTypes.OutQuint);
box.FadeIn(transition_length, Easing.OutQuint);
Text.FadeColour(Color4.White, transition_length, Easing.OutQuint);
}
private void fadeInactive()
{
box.FadeOut(transition_length, EasingTypes.OutQuint);
Text.FadeColour(AccentColour, transition_length, EasingTypes.OutQuint);
box.FadeOut(transition_length, Easing.OutQuint);
Text.FadeColour(AccentColour, transition_length, Easing.OutQuint);
}
protected override bool OnHover(InputState state)

View File

@ -49,14 +49,14 @@ namespace osu.Game.Graphics.UserInterface
private void fadeIn()
{
box.FadeIn(transition_length, EasingTypes.OutQuint);
text.FadeColour(Color4.White, transition_length, EasingTypes.OutQuint);
box.FadeIn(transition_length, Easing.OutQuint);
text.FadeColour(Color4.White, transition_length, Easing.OutQuint);
}
private void fadeOut()
{
box.FadeOut(transition_length, EasingTypes.OutQuint);
text.FadeColour(AccentColour, transition_length, EasingTypes.OutQuint);
box.FadeOut(transition_length, Easing.OutQuint);
text.FadeColour(AccentColour, transition_length, Easing.OutQuint);
}
protected override bool OnHover(InputState state)

View File

@ -1,9 +1,6 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Transforms;
using osu.Framework.MathUtils;
using System;
namespace osu.Game.Graphics.UserInterface
@ -13,8 +10,6 @@ namespace osu.Game.Graphics.UserInterface
/// </summary>
public class PercentageCounter : RollingCounter<double>
{
protected override Type TransformType => typeof(TransformAccuracy);
protected override double RollingDuration => 750;
private float epsilon => 1e-10f;
@ -44,23 +39,5 @@ namespace osu.Game.Graphics.UserInterface
{
Current.Value = Current + amount;
}
protected class TransformAccuracy : Transform<double, Drawable>
{
public virtual double CurrentValue
{
get
{
double time = Time?.Current ?? 0;
if (time < StartTime) return StartValue;
if (time >= EndTime) return EndValue;
return Interpolation.ValueAt(time, (float)StartValue, (float)EndValue, StartTime, EndTime, Easing);
}
}
public override void Apply(Drawable d) => ((PercentageCounter)d).DisplayedCount = CurrentValue;
public override void ReadIntoStartValue(Drawable d) => StartValue = ((PercentageCounter)d).DisplayedCount;
}
}
}

View File

@ -5,30 +5,21 @@ using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transforms;
using osu.Game.Graphics.Sprites;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using OpenTK.Graphics;
namespace osu.Game.Graphics.UserInterface
{
public abstract class RollingCounter<T> : Container, IHasAccentColour
where T : struct, IEquatable<T>
{
/// <summary>
/// The current value.
/// </summary>
public Bindable<T> Current = new Bindable<T>();
/// <summary>
/// Type of the Transform to use.
/// </summary>
/// <remarks>
/// Must be a subclass of Transform(T)
/// </remarks>
protected virtual Type TransformType => typeof(Transform<T, Drawable>);
protected SpriteText DisplayedCountSpriteText;
/// <summary>
@ -45,7 +36,7 @@ namespace osu.Game.Graphics.UserInterface
/// <summary>
/// Easing for the counter rollover animation.
/// </summary>
protected virtual EasingTypes RollingEasing => EasingTypes.OutQuint;
protected virtual Easing RollingEasing => Easing.OutQuint;
private T displayedCount;
@ -58,7 +49,8 @@ namespace osu.Game.Graphics.UserInterface
{
return displayedCount;
}
protected set
set
{
if (EqualityComparer<T>.Default.Equals(displayedCount, value))
return;
@ -133,7 +125,7 @@ namespace osu.Game.Graphics.UserInterface
/// </summary>
public virtual void StopRolling()
{
Flush(false, TransformType);
FinishTransforms(false, nameof(DisplayedCount));
DisplayedCount = Current;
}
@ -176,44 +168,15 @@ namespace osu.Game.Graphics.UserInterface
/// implement the rollover animation).
/// </summary>
/// <param name="currentValue">Count value before modification.</param>
/// <param name="newValue">Expected count value after modification-</param>
/// <seealso cref="TransformType"/>
/// <param name="newValue">Expected count value after modification.</param>
protected virtual void TransformCount(T currentValue, T newValue)
{
Debug.Assert(
typeof(Transform<T, Drawable>).IsAssignableFrom(TransformType),
@"transformType should be a subclass of Transform<T>."
);
TransformCount((Transform<T, Drawable>)Activator.CreateInstance(TransformType), currentValue, newValue);
}
/// <summary>
/// Intended to be used by TransformCount(T currentValue, T newValue).
/// </summary>
protected void TransformCount(Transform<T, Drawable> transform, T currentValue, T newValue)
{
Type type = transform.GetType();
Flush(false, type);
if (RollingDuration < 1)
{
DisplayedCount = Current;
return;
}
double rollingTotalDuration =
IsRollingProportional
? GetProportionalDuration(currentValue, newValue)
: RollingDuration;
transform.StartTime = TransformStartTime;
transform.EndTime = TransformStartTime + rollingTotalDuration;
transform.EndValue = newValue;
transform.Easing = RollingEasing;
Transforms.Add(transform);
this.TransformTo(nameof(DisplayedCount), newValue, rollingTotalDuration, RollingEasing);
}
}
}

View File

@ -2,18 +2,13 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Transforms;
using osu.Framework.MathUtils;
using System;
namespace osu.Game.Graphics.UserInterface
{
public class ScoreCounter : RollingCounter<double>
{
protected override Type TransformType => typeof(TransformScore);
protected override double RollingDuration => 1000;
protected override EasingTypes RollingEasing => EasingTypes.Out;
protected override Easing RollingEasing => Easing.Out;
public bool UseCommaSeparator;
@ -55,23 +50,5 @@ namespace osu.Game.Graphics.UserInterface
{
Current.Value = Current + amount;
}
protected class TransformScore : Transform<double, Drawable>
{
public virtual double CurrentValue
{
get
{
double time = Time?.Current ?? 0;
if (time < StartTime) return StartValue;
if (time >= EndTime) return EndValue;
return Interpolation.ValueAt(time, (float)StartValue, (float)EndValue, StartTime, EndTime, Easing);
}
}
public override void Apply(Drawable d) => ((ScoreCounter)d).DisplayedCount = CurrentValue;
public override void ReadIntoStartValue(Drawable d) => StartValue = ((ScoreCounter)d).DisplayedCount;
}
}
}

View File

@ -2,9 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Transforms;
using osu.Framework.MathUtils;
namespace osu.Game.Graphics.UserInterface
{
@ -13,8 +10,6 @@ namespace osu.Game.Graphics.UserInterface
/// </summary>
public class SimpleComboCounter : RollingCounter<int>
{
protected override Type TransformType => typeof(TransformCounterCount);
protected override double RollingDuration => 750;
public SimpleComboCounter()
@ -36,23 +31,5 @@ namespace osu.Game.Graphics.UserInterface
{
Current.Value = Current + amount;
}
private class TransformCounterCount : Transform<int, Drawable>
{
public int CurrentValue
{
get
{
double time = Time?.Current ?? 0;
if (time < StartTime) return StartValue;
if (time >= EndTime) return EndValue;
return (int)Interpolation.ValueAt(time, StartValue, EndValue, StartTime, EndTime, Easing);
}
}
public override void Apply(Drawable d) => ((SimpleComboCounter)d).DisplayedCount = CurrentValue;
public override void ReadIntoStartValue(Drawable d) => StartValue = ((SimpleComboCounter)d).DisplayedCount;
}
}
}

View File

@ -24,7 +24,7 @@ namespace osu.Game.Graphics.UserInterface
private double animationDelay => 80;
private double scalingDuration => 1000;
private EasingTypes scalingEasing => EasingTypes.OutElasticHalf;
private Easing scalingEasing => Easing.OutElasticHalf;
private float minStarScale => 0.4f;
private double fadingDuration => 100;
@ -122,7 +122,7 @@ namespace osu.Game.Graphics.UserInterface
if (value <= i)
return minStarScale;
return i + 1 <= value ? 1.0f : (float)Interpolation.ValueAt(value, minStarScale, 1.0f, i, i + 1);
return i + 1 <= value ? 1.0f : Interpolation.ValueAt(value, minStarScale, 1.0f, i, i + 1);
}
private void transformCount(float newValue)
@ -133,12 +133,8 @@ namespace osu.Game.Graphics.UserInterface
star.ClearTransforms(true);
var delay = (countStars <= newValue ? Math.Max(i - countStars, 0) : Math.Max(countStars - 1 - i, 0)) * animationDelay;
using (BeginDelayedSequence(delay, true))
{
star.FadeTo(i < newValue ? 1.0f : minStarAlpha, fadingDuration);
star.Icon.ScaleTo(getStarScale(i, newValue), scalingDuration, scalingEasing);
}
star.Delay(delay).FadeTo(i < newValue ? 1.0f : minStarAlpha, fadingDuration);
star.Icon.Delay(delay).ScaleTo(getStarScale(i, newValue), scalingDuration, scalingEasing);
i++;
}

View File

@ -173,20 +173,20 @@ namespace osu.Game.Graphics.UserInterface
protected override bool OnHover(InputState state)
{
ResizeTo(SIZE_EXTENDED, transform_time, EasingTypes.OutElastic);
IconLayer.FadeColour(HoverColour, transform_time, EasingTypes.OutElastic);
this.ResizeTo(SIZE_EXTENDED, transform_time, Easing.OutElastic);
IconLayer.FadeColour(HoverColour, transform_time, Easing.OutElastic);
bouncingIcon.ScaleTo(1.1f, transform_time, EasingTypes.OutElastic);
bouncingIcon.ScaleTo(1.1f, transform_time, Easing.OutElastic);
return true;
}
protected override void OnHoverLost(InputState state)
{
ResizeTo(SIZE_RETRACTED, transform_time, EasingTypes.OutElastic);
IconLayer.FadeColour(TextLayer.Colour, transform_time, EasingTypes.OutElastic);
this.ResizeTo(SIZE_RETRACTED, transform_time, Easing.OutElastic);
IconLayer.FadeColour(TextLayer.Colour, transform_time, Easing.OutElastic);
bouncingIcon.ScaleTo(1, transform_time, EasingTypes.OutElastic);
bouncingIcon.ScaleTo(1, transform_time, Easing.OutElastic);
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
@ -205,7 +205,7 @@ namespace osu.Game.Graphics.UserInterface
Add(flash);
flash.Alpha = 1;
flash.FadeOut(500, EasingTypes.OutQuint);
flash.FadeOut(500, Easing.OutQuint);
flash.Expire();
return base.OnClick(state);
@ -245,9 +245,9 @@ namespace osu.Game.Graphics.UserInterface
if (beatIndex < 0) return;
icon.ScaleTo(1 - 0.1f * amplitudeAdjust, beat_in_time, EasingTypes.Out);
using (icon.BeginDelayedSequence(beat_in_time))
icon.ScaleTo(1, beatLength * 2, EasingTypes.OutQuint);
icon.ScaleTo(1 - 0.1f * amplitudeAdjust, beat_in_time, Easing.Out)
.Then()
.ScaleTo(1, beatLength * 2, Easing.OutQuint);
}
}
}

View File

@ -93,21 +93,20 @@ namespace osu.Game.Graphics.UserInterface.Volume
protected override void PopIn()
{
ClearTransforms();
FadeIn(100);
this.FadeIn(100);
schedulePopOut();
}
protected override void PopOut()
{
FadeOut(100);
this.FadeOut(100);
}
private void schedulePopOut()
{
popOutDelegate?.Cancel();
Delay(1000);
popOutDelegate = Schedule(Hide);
this.Delay(1000).Schedule(Hide, out popOutDelegate);
}
}
}

View File

@ -82,6 +82,6 @@ namespace osu.Game.Graphics.UserInterface.Volume
return true;
}
private void updateFill() => meterFill.ScaleTo(new Vector2(1, (float)Volume), 300, EasingTypes.OutQuint);
private void updateFill() => meterFill.ScaleTo(new Vector2(1, (float)Volume), 300, Easing.OutQuint);
}
}

22
osu.Game/IO/FileInfo.cs Normal file
View File

@ -0,0 +1,22 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.IO;
using SQLite.Net.Attributes;
namespace osu.Game.IO
{
public class FileInfo
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
[Indexed(Unique = true)]
public string Hash { get; set; }
public string StoragePath => Path.Combine(Hash.Remove(1), Hash.Remove(2), Hash);
[Indexed]
public int ReferenceCount { get; set; }
}
}

159
osu.Game/IO/FileStore.cs Normal file
View File

@ -0,0 +1,159 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using osu.Framework.Extensions;
using osu.Framework.IO.Stores;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Game.Database;
using SQLite.Net;
namespace osu.Game.IO
{
/// <summary>
/// Handles the Store and retrieval of Files/FileSets to the database backing
/// </summary>
public class FileStore : DatabaseBackedStore
{
private const string prefix = "files";
public readonly ResourceStore<byte[]> Store;
protected override int StoreVersion => 2;
public FileStore(SQLiteConnection connection, Storage storage) : base(connection, storage)
{
Store = new NamespacedResourceStore<byte[]>(new StorageBackedResourceStore(storage), prefix);
}
protected override Type[] ValidTypes => new[] {
typeof(FileInfo),
};
protected override void Prepare(bool reset = false)
{
if (reset)
{
// in earlier versions we stored beatmaps as solid archives, but not any more.
if (Storage.ExistsDirectory("beatmaps"))
Storage.DeleteDirectory("beatmaps");
if (Storage.ExistsDirectory(prefix))
Storage.DeleteDirectory(prefix);
Connection.DropTable<FileInfo>();
}
Connection.CreateTable<FileInfo>();
}
protected override void StartupTasks()
{
base.StartupTasks();
deletePending();
}
/// <summary>
/// Perform migrations between two store versions.
/// </summary>
/// <param name="currentVersion">The current store version. This will be zero on a fresh database initialisation.</param>
/// <param name="targetVersion">The target version which we are migrating to (equal to the current <see cref="StoreVersion"/>).</param>
protected override void PerformMigration(int currentVersion, int targetVersion)
{
base.PerformMigration(currentVersion, targetVersion);
while (currentVersion++ < targetVersion)
{
switch (currentVersion)
{
case 1:
case 2:
// cannot migrate; breaking underlying changes.
Reset();
break;
}
}
}
public FileInfo Add(Stream data)
{
string hash = data.ComputeSHA2Hash();
var info = new FileInfo { Hash = hash };
var existing = Connection.Table<FileInfo>().FirstOrDefault(f => f.Hash == info.Hash);
if (existing != null)
{
info = existing;
}
else
{
string path = Path.Combine(prefix, info.StoragePath);
data.Seek(0, SeekOrigin.Begin);
if (!Storage.Exists(path))
using (var output = Storage.GetStream(path, FileAccess.Write))
data.CopyTo(output);
data.Seek(0, SeekOrigin.Begin);
Connection.Insert(info);
}
Reference(new[] { info });
return info;
}
public void Reference(IEnumerable<FileInfo> files)
{
Connection.RunInTransaction(() =>
{
var incrementedFiles = files.GroupBy(f => f.ID).Select(f =>
{
var accurateRefCount = Connection.Get<FileInfo>(f.First().ID);
accurateRefCount.ReferenceCount += f.Count();
return accurateRefCount;
});
Connection.UpdateAll(incrementedFiles);
});
}
public void Dereference(IEnumerable<FileInfo> files)
{
Connection.RunInTransaction(() =>
{
var incrementedFiles = files.GroupBy(f => f.ID).Select(f =>
{
var accurateRefCount = Connection.Get<FileInfo>(f.First().ID);
accurateRefCount.ReferenceCount -= f.Count();
return accurateRefCount;
});
Connection.UpdateAll(incrementedFiles);
});
}
private void deletePending()
{
foreach (var f in QueryAndPopulate<FileInfo>(f => f.ReferenceCount < 1))
{
try
{
Connection.Delete(f);
Storage.Delete(Path.Combine(prefix, f.StoragePath));
}
catch (Exception e)
{
Logger.Error(e, $@"Could not delete beatmap {f}");
}
}
}
}
}

View File

@ -4,15 +4,15 @@
using System.Diagnostics;
using System.Threading.Tasks;
using osu.Framework.Platform;
using osu.Game.Database;
using osu.Game.Beatmaps;
namespace osu.Game.IPC
{
public class BeatmapIPCChannel : IpcChannel<BeatmapImportMessage>
{
private readonly BeatmapDatabase beatmaps;
private readonly BeatmapManager beatmaps;
public BeatmapIPCChannel(IIpcHost host, BeatmapDatabase beatmaps = null)
public BeatmapIPCChannel(IIpcHost host, BeatmapManager beatmaps = null)
: base(host)
{
this.beatmaps = beatmaps;

View File

@ -4,15 +4,15 @@
using System.Diagnostics;
using System.Threading.Tasks;
using osu.Framework.Platform;
using osu.Game.Database;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.IPC
{
public class ScoreIPCChannel : IpcChannel<ScoreImportMessage>
{
private readonly ScoreDatabase scores;
private readonly ScoreStore scores;
public ScoreIPCChannel(IIpcHost host, ScoreDatabase scores = null)
public ScoreIPCChannel(IIpcHost host, ScoreStore scores = null)
: base(host)
{
this.scores = scores;

View File

@ -117,7 +117,7 @@ namespace osu.Game.Online.API
if (!authentication.HasValidAccessToken && !authentication.AuthenticateWithLogin(Username, Password))
{
//todo: this fails even on network-related issues. we should probably handle those differently.
//NotificationManager.ShowMessage("Login failed!");
//NotificationOverlay.ShowMessage("Login failed!");
log.Add(@"Login failed!");
Password = null;
continue;
@ -254,7 +254,7 @@ namespace osu.Game.Online.API
{
//OsuGame.Scheduler.Add(delegate
{
//NotificationManager.ShowMessage($@"We just went {newState}!", newState == APIState.Online ? Color4.YellowGreen : Color4.OrangeRed, 5000);
//NotificationOverlay.ShowMessage($@"We just went {newState}!", newState == APIState.Online ? Color4.YellowGreen : Color4.OrangeRed, 5000);
log.Add($@"We just went {newState}!");
Scheduler.Add(delegate
{

View File

@ -2,7 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using Newtonsoft.Json;
using osu.Game.Database;
using osu.Game.Beatmaps;
namespace osu.Game.Online.API.Requests
{

View File

@ -4,9 +4,10 @@
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using osu.Game.Database;
using osu.Game.Beatmaps;
using osu.Game.Overlays;
using osu.Game.Overlays.Direct;
using osu.Game.Rulesets;
namespace osu.Game.Online.API.Requests
{
@ -48,7 +49,7 @@ namespace osu.Game.Online.API.Requests
[JsonProperty(@"beatmaps")]
private IEnumerable<GetBeatmapSetsBeatmapResponse> beatmaps { get; set; }
public BeatmapSetInfo ToBeatmapSet(RulesetDatabase rulesets)
public BeatmapSetInfo ToBeatmapSet(RulesetStore rulesets)
{
return new BeatmapSetInfo
{
@ -78,7 +79,7 @@ namespace osu.Game.Online.API.Requests
[JsonProperty(@"difficulty_rating")]
private double starDifficulty { get; set; }
public BeatmapInfo ToBeatmap(RulesetDatabase rulesets)
public BeatmapInfo ToBeatmap(RulesetStore rulesets)
{
return new BeatmapInfo
{

View File

@ -4,7 +4,7 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using osu.Framework.IO.Network;
using osu.Game.Database;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Online.API.Requests

View File

@ -2,7 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Configuration;
using osu.Game.Database;
using osu.Game.Beatmaps;
using osu.Game.Users;
namespace osu.Game.Online.Multiplayer

View File

@ -21,10 +21,10 @@ using OpenTK;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Threading;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Rulesets.Scoring;
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets;
using osu.Game.Screens.Play;
namespace osu.Game
@ -37,7 +37,7 @@ namespace osu.Game
private MusicController musicController;
private NotificationManager notificationManager;
private NotificationOverlay notificationOverlay;
private DialogOverlay dialogOverlay;
@ -80,6 +80,11 @@ namespace osu.Game
public void ToggleDirect() => direct.ToggleVisibility();
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) =>
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
[BackgroundDependencyLoader]
private void load(FrameworkConfigManager frameworkConfig)
{
@ -94,13 +99,13 @@ namespace osu.Game
if (args?.Length > 0)
{
var paths = args.Where(a => !a.StartsWith(@"-"));
Task.Run(() => BeatmapDatabase.Import(paths.ToArray()));
Task.Run(() => BeatmapManager.Import(paths.ToArray()));
}
Dependencies.Cache(this);
dependencies.Cache(this);
configRuleset = LocalConfig.GetBindable<int>(OsuSetting.Ruleset);
Ruleset.Value = RulesetDatabase.GetRuleset(configRuleset.Value);
Ruleset.Value = RulesetStore.GetRuleset(configRuleset.Value);
Ruleset.ValueChanged += r => configRuleset.Value = r.ID ?? 0;
}
@ -121,14 +126,13 @@ namespace osu.Game
if (!menu.IsCurrentScreen)
{
menu.MakeCurrent();
Delay(500);
scoreLoad = Schedule(() => LoadScore(s));
this.Delay(500).Schedule(() => LoadScore(s), out scoreLoad);
return;
}
if (s.Beatmap == null)
{
notificationManager.Post(new SimpleNotification
notificationOverlay.Post(new SimpleNotification
{
Text = @"Tried to load a score for a beatmap we don't have!",
Icon = FontAwesome.fa_life_saver,
@ -136,7 +140,7 @@ namespace osu.Game
return;
}
Beatmap.Value = BeatmapDatabase.GetWorkingBeatmap(s.Beatmap);
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(s.Beatmap);
menu.Push(new PlayerLoader(new ReplayPlayer(s.Replay)));
}
@ -145,6 +149,9 @@ namespace osu.Game
{
base.LoadComplete();
// hook up notifications to components.
BeatmapManager.PostNotification = n => notificationOverlay?.Post(n);
AddRange(new Drawable[] {
new VolumeControlReceptor
{
@ -175,45 +182,45 @@ namespace osu.Game
LoadComponentAsync(direct = new DirectOverlay { Depth = -1 }, mainContent.Add);
LoadComponentAsync(social = new SocialOverlay { Depth = -1 }, mainContent.Add);
LoadComponentAsync(chat = new ChatOverlay { Depth = -1 }, mainContent.Add);
LoadComponentAsync(userProfile = new UserProfileOverlay { Depth = -1 }, mainContent.Add);
LoadComponentAsync(settings = new SettingsOverlay { Depth = -1 }, overlayContent.Add);
LoadComponentAsync(userProfile = new UserProfileOverlay { Depth = -2 }, mainContent.Add);
LoadComponentAsync(musicController = new MusicController
{
Depth = -2,
Depth = -3,
Position = new Vector2(0, Toolbar.HEIGHT),
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
}, overlayContent.Add);
LoadComponentAsync(notificationManager = new NotificationManager
LoadComponentAsync(notificationOverlay = new NotificationOverlay
{
Depth = -2,
Depth = -3,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
}, overlayContent.Add);
LoadComponentAsync(dialogOverlay = new DialogOverlay
{
Depth = -4,
Depth = -5,
}, overlayContent.Add);
Logger.NewEntry += entry =>
{
if (entry.Level < LogLevel.Important) return;
notificationManager.Post(new SimpleNotification
notificationOverlay.Post(new SimpleNotification
{
Text = $@"{entry.Level}: {entry.Message}"
});
};
Dependencies.Cache(settings);
Dependencies.Cache(social);
Dependencies.Cache(chat);
Dependencies.Cache(userProfile);
Dependencies.Cache(musicController);
Dependencies.Cache(notificationManager);
Dependencies.Cache(dialogOverlay);
dependencies.Cache(settings);
dependencies.Cache(social);
dependencies.Cache(chat);
dependencies.Cache(userProfile);
dependencies.Cache(musicController);
dependencies.Cache(notificationOverlay);
dependencies.Cache(dialogOverlay);
// ensure both overlays aren't presented at the same time
chat.StateChanged += (container, state) => social.State = state == Visibility.Visible ? Visibility.Hidden : social.State;
@ -221,7 +228,7 @@ namespace osu.Game
LoadComponentAsync(Toolbar = new Toolbar
{
Depth = -3,
Depth = -4,
OnHome = delegate { intro?.ChildScreen?.MakeCurrent(); },
}, overlayContent.Add);
@ -230,10 +237,10 @@ namespace osu.Game
switch (settings.State)
{
case Visibility.Hidden:
intro.MoveToX(0, SettingsOverlay.TRANSITION_LENGTH, EasingTypes.OutQuint);
intro.MoveToX(0, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint);
break;
case Visibility.Visible:
intro.MoveToX(SettingsOverlay.SIDEBAR_WIDTH / 2, SettingsOverlay.TRANSITION_LENGTH, EasingTypes.OutQuint);
intro.MoveToX(SettingsOverlay.SIDEBAR_WIDTH / 2, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint);
break;
}
};
@ -327,6 +334,7 @@ namespace osu.Game
direct.State = Visibility.Hidden;
social.State = Visibility.Hidden;
userProfile.State = Visibility.Hidden;
notificationOverlay.State = Visibility.Hidden;
}
else
{

View File

@ -11,15 +11,17 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.IO.Stores;
using osu.Framework.Platform;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.IO;
using osu.Game.Configuration;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.Cursor;
using osu.Game.Graphics.Processing;
using osu.Game.Online.API;
using SQLite.Net;
using osu.Framework.Graphics.Performance;
using osu.Game.Database;
using osu.Game.IO;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Scoring;
namespace osu.Game
{
@ -27,11 +29,13 @@ namespace osu.Game
{
protected OsuConfigManager LocalConfig;
protected BeatmapDatabase BeatmapDatabase;
protected BeatmapManager BeatmapManager;
protected RulesetDatabase RulesetDatabase;
protected RulesetStore RulesetStore;
protected ScoreDatabase ScoreDatabase;
protected FileStore FileStore;
protected ScoreStore ScoreStore;
protected override string MainResourceFile => @"osu.Game.Resources.dll";
@ -81,21 +85,29 @@ namespace osu.Game
Name = @"osu!lazer";
}
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) =>
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
[BackgroundDependencyLoader]
private void load()
{
Dependencies.Cache(this);
Dependencies.Cache(LocalConfig);
dependencies.Cache(this);
dependencies.Cache(LocalConfig);
SQLiteConnection connection = Host.Storage.GetDatabase(@"client");
Dependencies.Cache(RulesetDatabase = new RulesetDatabase(Host.Storage, connection));
Dependencies.Cache(BeatmapDatabase = new BeatmapDatabase(Host.Storage, connection, RulesetDatabase, Host));
Dependencies.Cache(ScoreDatabase = new ScoreDatabase(Host.Storage, connection, Host, BeatmapDatabase));
Dependencies.Cache(new OsuColour());
connection.CreateTable<StoreVersion>();
dependencies.Cache(RulesetStore = new RulesetStore(connection));
dependencies.Cache(FileStore = new FileStore(connection, Host.Storage));
dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, FileStore, connection, RulesetStore, Host));
dependencies.Cache(ScoreStore = new ScoreStore(Host.Storage, connection, Host, BeatmapManager));
dependencies.Cache(new OsuColour());
//this completely overrides the framework default. will need to change once we make a proper FontStore.
Dependencies.Cache(Fonts = new FontStore { ScaleAdjust = 100 }, true);
dependencies.Cache(Fonts = new FontStore { ScaleAdjust = 100 }, true);
Fonts.AddStore(new GlyphStore(Resources, @"Fonts/FontAwesome"));
Fonts.AddStore(new GlyphStore(Resources, @"Fonts/osuFont"));
@ -123,19 +135,35 @@ namespace osu.Game
var defaultBeatmap = new DummyWorkingBeatmap(this);
Beatmap = new NonNullableBindable<WorkingBeatmap>(defaultBeatmap);
BeatmapDatabase.DefaultBeatmap = defaultBeatmap;
BeatmapManager.DefaultBeatmap = defaultBeatmap;
OszArchiveReader.Register();
Dependencies.Cache(API = new APIAccess
dependencies.Cache(API = new APIAccess
{
Username = LocalConfig.Get<string>(OsuSetting.Username),
Token = LocalConfig.Get<string>(OsuSetting.Token)
});
Beatmap.ValueChanged += b =>
{
// compare to last baetmap as sometimes the two may share a track representation (optimisation, see WorkingBeatmap.TransferTo)
if (lastBeatmap?.Track != b.Track)
{
// this disposal is done to stop the audio track.
// it may not be exactly what we want for cases beatmaps are reused, as it will
// trigger a fresh load of contained resources.
lastBeatmap?.Dispose();
Audio.Track.AddItem(b.Track);
}
lastBeatmap = b;
};
API.Register(this);
}
private WorkingBeatmap lastBeatmap;
public void APIStateChanged(APIAccess api, APIState state)
{
switch (state)

View File

@ -39,7 +39,7 @@ namespace osu.Game.Overlays.Chat
{
set
{
FadeTo(value ? 1f : 0f, 100);
this.FadeTo(value ? 1f : 0f, 100);
}
}
@ -156,7 +156,7 @@ namespace osu.Game.Overlays.Chat
protected override bool OnHover(InputState state)
{
if (!channel.Joined.Value)
name.FadeColour(hoverColour, 50, EasingTypes.OutQuint);
name.FadeColour(hoverColour, 50, Easing.OutQuint);
return base.OnHover(state);
}
@ -175,14 +175,14 @@ namespace osu.Game.Overlays.Chat
joinedCheckmark.FadeTo(1f, transition_duration);
topic.FadeTo(0.8f, transition_duration);
topic.FadeColour(Color4.White, transition_duration);
FadeColour(joinedColour, transition_duration);
this.FadeColour(joinedColour, transition_duration);
}
else
{
joinedCheckmark.FadeTo(0f, transition_duration);
topic.FadeTo(1f, transition_duration);
topic.FadeColour(topicColour, transition_duration);
FadeColour(Color4.White, transition_duration);
this.FadeColour(Color4.White, transition_duration);
}
}
}

View File

@ -23,7 +23,7 @@ namespace osu.Game.Overlays.Chat
{
set
{
FadeTo(value ? 1f : 0f, 100);
this.FadeTo(value ? 1f : 0f, 100);
}
}

View File

@ -92,7 +92,7 @@ namespace osu.Game.Overlays.Chat
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
LayoutDuration = 200,
LayoutEasing = EasingTypes.OutQuint,
LayoutEasing = Easing.OutQuint,
Spacing = new Vector2(0f, 20f),
Padding = new MarginPadding { Vertical = 20, Left = WIDTH_PADDING },
},
@ -158,10 +158,10 @@ namespace osu.Game.Overlays.Chat
protected override void PopIn()
{
if (Alpha == 0) MoveToY(DrawHeight);
if (Alpha == 0) this.MoveToY(DrawHeight);
FadeIn(transition_duration, EasingTypes.OutQuint);
MoveToY(0, transition_duration, EasingTypes.OutQuint);
this.FadeIn(transition_duration, Easing.OutQuint);
this.MoveToY(0, transition_duration, Easing.OutQuint);
search.HoldFocus = true;
base.PopIn();
@ -169,8 +169,8 @@ namespace osu.Game.Overlays.Chat
protected override void PopOut()
{
FadeOut(transition_duration, EasingTypes.InSine);
MoveToY(DrawHeight, transition_duration, EasingTypes.InSine);
this.FadeOut(transition_duration, Easing.InSine);
this.MoveToY(DrawHeight, transition_duration, Easing.InSine);
search.HoldFocus = false;
base.PopOut();

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
@ -11,6 +12,8 @@ using OpenTK.Graphics;
using osu.Framework.Graphics.Effects;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Allocation;
using osu.Game.Users;
using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays.Chat
{
@ -62,6 +65,8 @@ namespace osu.Game.Overlays.Chat
private const float message_padding = 200;
private const float text_size = 20;
private Action<User> loadProfile;
private Color4 customUsernameColour;
public ChatLine(Message message)
@ -74,10 +79,11 @@ namespace osu.Game.Overlays.Chat
Padding = new MarginPadding { Left = padding, Right = padding };
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
[BackgroundDependencyLoader(true)]
private void load(OsuColour colours, UserProfileOverlay profile)
{
customUsernameColour = colours.ChatBlue;
loadProfile = u => profile?.ShowUser(u);
}
protected override void LoadComplete()
@ -87,8 +93,6 @@ namespace osu.Game.Overlays.Chat
bool hasBackground = !string.IsNullOrEmpty(Message.Sender.Colour);
Drawable username = new OsuSpriteText
{
Origin = Anchor.TopRight,
Anchor = Anchor.TopRight,
Font = @"Exo2.0-BoldItalic",
Text = $@"{Message.Sender.Username}" + (hasBackground ? "" : ":"),
Colour = hasBackground ? customUsernameColour : username_colours[Message.UserId % username_colours.Length],
@ -132,7 +136,7 @@ namespace osu.Game.Overlays.Chat
new Container
{
Size = new Vector2(message_padding, text_size),
Children = new[]
Children = new Drawable[]
{
new OsuSpriteText
{
@ -144,7 +148,14 @@ namespace osu.Game.Overlays.Chat
TextSize = text_size * 0.75f,
Alpha = 0.4f,
},
username
new ClickableContainer
{
AutoSizeAxes = Axes.Both,
Origin = Anchor.TopRight,
Anchor = Anchor.TopRight,
Child = username,
Action = () => loadProfile(Message.Sender),
},
}
},
new Container
@ -154,10 +165,12 @@ namespace osu.Game.Overlays.Chat
Padding = new MarginPadding { Left = message_padding + padding },
Children = new Drawable[]
{
new OsuSpriteText
new OsuTextFlowContainer(t =>
{
t.TextSize = text_size;
})
{
Text = Message.Content,
TextSize = text_size,
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
}

View File

@ -86,30 +86,30 @@ namespace osu.Game.Overlays.Chat
private void fadeActive()
{
ResizeTo(new Vector2(Width, 1.1f), transition_length, EasingTypes.OutQuint);
this.ResizeTo(new Vector2(Width, 1.1f), transition_length, Easing.OutQuint);
box.FadeColour(backgroundActive, transition_length, EasingTypes.OutQuint);
highlightBox.FadeIn(transition_length, EasingTypes.OutQuint);
box.FadeColour(backgroundActive, transition_length, Easing.OutQuint);
highlightBox.FadeIn(transition_length, Easing.OutQuint);
text.FadeOut(transition_length, EasingTypes.OutQuint);
textBold.FadeIn(transition_length, EasingTypes.OutQuint);
text.FadeOut(transition_length, Easing.OutQuint);
textBold.FadeIn(transition_length, Easing.OutQuint);
}
private void fadeInactive()
{
ResizeTo(new Vector2(Width, 1), transition_length, EasingTypes.OutQuint);
this.ResizeTo(new Vector2(Width, 1), transition_length, Easing.OutQuint);
box.FadeColour(backgroundInactive, transition_length, EasingTypes.OutQuint);
highlightBox.FadeOut(transition_length, EasingTypes.OutQuint);
box.FadeColour(backgroundInactive, transition_length, Easing.OutQuint);
highlightBox.FadeOut(transition_length, Easing.OutQuint);
text.FadeIn(transition_length, EasingTypes.OutQuint);
textBold.FadeOut(transition_length, EasingTypes.OutQuint);
text.FadeIn(transition_length, Easing.OutQuint);
textBold.FadeOut(transition_length, Easing.OutQuint);
}
protected override bool OnHover(InputState state)
{
if (!Active)
box.FadeColour(backgroundHover, transition_length, EasingTypes.OutQuint);
box.FadeColour(backgroundHover, transition_length, Easing.OutQuint);
return true;
}

View File

@ -52,6 +52,7 @@ namespace osu.Game.Overlays
private readonly ChatTabControl channelTabs;
private readonly Container chatContainer;
private readonly Container tabsArea;
private readonly Box chatBackground;
private readonly Box tabBackground;
@ -144,7 +145,7 @@ namespace osu.Game.Overlays
loading = new LoadingAnimation(),
}
},
new Container
tabsArea = new Container
{
Name = @"tabs area",
RelativeSizeAxes = Axes.X,
@ -177,8 +178,8 @@ namespace osu.Game.Overlays
inputTextBox.HoldFocus = false;
if (1f - chatHeight.Value < channel_selection_min_height)
{
chatContainer.ResizeHeightTo(1f - channel_selection_min_height, 800, EasingTypes.OutQuint);
channelSelectionContainer.ResizeHeightTo(channel_selection_min_height, 800, EasingTypes.OutQuint);
chatContainer.ResizeHeightTo(1f - channel_selection_min_height, 800, Easing.OutQuint);
channelSelectionContainer.ResizeHeightTo(channel_selection_min_height, 800, Easing.OutQuint);
channelSelection.Show();
chatHeight.Value = 1f - channel_selection_min_height;
}
@ -191,10 +192,13 @@ namespace osu.Game.Overlays
}
private double startDragChatHeight;
private bool isDragging;
protected override bool OnDragStart(InputState state)
{
if (!channelTabs.IsHovered)
isDragging = tabsArea.IsHovered;
if (!isDragging)
return base.OnDragStart(state);
startDragChatHeight = chatHeight.Value;
@ -203,10 +207,20 @@ namespace osu.Game.Overlays
protected override bool OnDrag(InputState state)
{
Trace.Assert(state.Mouse.PositionMouseDown != null);
if (isDragging)
{
Trace.Assert(state.Mouse.PositionMouseDown != null);
chatHeight.Value = startDragChatHeight - (state.Mouse.Position.Y - state.Mouse.PositionMouseDown.Value.Y) / Parent.DrawSize.Y;
return base.OnDrag(state);
chatHeight.Value = startDragChatHeight - (state.Mouse.Position.Y - state.Mouse.PositionMouseDown.Value.Y) / Parent.DrawSize.Y;
}
return true;
}
protected override bool OnDragEnd(InputState state)
{
isDragging = false;
return base.OnDragEnd(state);
}
public void APIStateChanged(APIAccess api, APIState state)
@ -235,8 +249,8 @@ namespace osu.Game.Overlays
protected override void PopIn()
{
MoveToY(0, transition_length, EasingTypes.OutQuint);
FadeIn(transition_length, EasingTypes.OutQuint);
this.MoveToY(0, transition_length, Easing.OutQuint);
this.FadeIn(transition_length, Easing.OutQuint);
inputTextBox.HoldFocus = true;
base.PopIn();
@ -244,8 +258,8 @@ namespace osu.Game.Overlays
protected override void PopOut()
{
MoveToY(Height, transition_length, EasingTypes.InSine);
FadeOut(transition_length, EasingTypes.InSine);
this.MoveToY(Height, transition_length, Easing.InSine);
this.FadeOut(transition_length, Easing.InSine);
inputTextBox.HoldFocus = false;
base.PopOut();
@ -328,7 +342,7 @@ namespace osu.Game.Overlays
var loaded = loadedChannels.Find(d => d.Channel == value);
if (loaded == null)
{
currentChannelContainer.FadeOut(500, EasingTypes.OutQuint);
currentChannelContainer.FadeOut(500, Easing.OutQuint);
loading.Show();
loaded = new DrawableChannel(currentChannel);
@ -340,7 +354,7 @@ namespace osu.Game.Overlays
currentChannelContainer.Clear(false);
currentChannelContainer.Add(loaded);
currentChannelContainer.FadeIn(500, EasingTypes.OutQuint);
currentChannelContainer.FadeIn(500, Easing.OutQuint);
});
}
else

View File

@ -115,17 +115,17 @@ namespace osu.Game.Overlays.Dialog
ring.ResizeTo(ringMinifiedSize);
}
content.FadeIn(ENTER_DURATION, EasingTypes.OutQuint);
ring.ResizeTo(ringSize, ENTER_DURATION, EasingTypes.OutQuint);
buttonsContainer.TransformSpacingTo(Vector2.Zero, ENTER_DURATION, EasingTypes.OutQuint);
buttonsContainer.MoveToY(0, ENTER_DURATION, EasingTypes.OutQuint);
content.FadeIn(ENTER_DURATION, Easing.OutQuint);
ring.ResizeTo(ringSize, ENTER_DURATION, Easing.OutQuint);
buttonsContainer.TransformSpacingTo(Vector2.Zero, ENTER_DURATION, Easing.OutQuint);
buttonsContainer.MoveToY(0, ENTER_DURATION, Easing.OutQuint);
}
protected override void PopOut()
{
base.PopOut();
content.FadeOut(EXIT_DURATION, EasingTypes.InSine);
content.FadeOut(EXIT_DURATION, Easing.InSine);
}
public PopupDialog()

View File

@ -35,8 +35,7 @@ namespace osu.Game.Overlays
if (v != Visibility.Hidden) return;
//handle the dialog being dismissed.
dialog.Delay(PopupDialog.EXIT_DURATION);
dialog.Expire();
dialog.Delay(PopupDialog.EXIT_DURATION).Expire();
if (dialog == currentDialog)
State = Visibility.Hidden;
@ -45,13 +44,13 @@ namespace osu.Game.Overlays
protected override void PopIn()
{
base.PopIn();
FadeIn(PopupDialog.ENTER_DURATION, EasingTypes.OutQuint);
this.FadeIn(PopupDialog.ENTER_DURATION, Easing.OutQuint);
}
protected override void PopOut()
{
base.PopOut();
FadeOut(PopupDialog.EXIT_DURATION, EasingTypes.InSine);
this.FadeOut(PopupDialog.EXIT_DURATION, Easing.InSine);
}
public DialogOverlay()

View File

@ -8,10 +8,10 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Localisation;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
namespace osu.Game.Overlays.Direct
{
@ -41,9 +41,9 @@ namespace osu.Game.Overlays.Direct
{
base.LoadComplete();
FadeInFromZero(200, EasingTypes.Out);
this.FadeInFromZero(200, Easing.Out);
bottomPanel.LayoutDuration = 200;
bottomPanel.LayoutEasing = EasingTypes.Out;
bottomPanel.LayoutEasing = Easing.Out;
bottomPanel.Origin = Anchor.BottomLeft;
}

View File

@ -9,11 +9,11 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Colour;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Database;
using osu.Framework.Allocation;
using osu.Framework.Localisation;
using osu.Framework.Input;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays.Direct
@ -43,7 +43,7 @@ namespace osu.Game.Overlays.Direct
{
base.LoadComplete();
FadeInFromZero(200, EasingTypes.Out);
this.FadeInFromZero(200, Easing.Out);
}
[BackgroundDependencyLoader]
@ -60,7 +60,7 @@ namespace osu.Game.Overlays.Direct
new Box
{
RelativeSizeAxes = Axes.Both,
ColourInfo = ColourInfo.GradientHorizontal(Color4.Black.Opacity(0.25f), Color4.Black.Opacity(0.75f)),
Colour = ColourInfo.GradientHorizontal(Color4.Black.Opacity(0.25f), Color4.Black.Opacity(0.75f)),
},
new Container
{
@ -171,25 +171,25 @@ namespace osu.Game.Overlays.Direct
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
icon.ScaleTo(0.9f, 1000, EasingTypes.Out);
icon.ScaleTo(0.9f, 1000, Easing.Out);
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
icon.ScaleTo(1f, 500, EasingTypes.OutElastic);
icon.ScaleTo(1f, 500, Easing.OutElastic);
return base.OnMouseUp(state, args);
}
protected override bool OnHover(InputState state)
{
icon.ScaleTo(1.1f, 500, EasingTypes.OutElastic);
icon.ScaleTo(1.1f, 500, Easing.OutElastic);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
icon.ScaleTo(1f, 500, EasingTypes.OutElastic);
icon.ScaleTo(1f, 500, Easing.OutElastic);
}
}
}

View File

@ -6,8 +6,8 @@ using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
@ -38,7 +38,7 @@ namespace osu.Game.Overlays.Direct
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
FillMode = FillMode.Fill,
OnLoadComplete = d => d.FadeInFromZero(400, EasingTypes.Out),
OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out),
})
{
RelativeSizeAxes = Axes.Both,

View File

@ -7,10 +7,11 @@ using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Database;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Overlays.SearchableList;
using osu.Game.Rulesets;
namespace osu.Game.Overlays.Direct
{
@ -33,7 +34,7 @@ namespace osu.Game.Overlays.Direct
}
[BackgroundDependencyLoader(true)]
private void load(OsuGame game, RulesetDatabase rulesets, OsuColour colours)
private void load(OsuGame game, RulesetStore rulesets, OsuColour colours)
{
DisplayStyleControl.Dropdown.AccentColour = colours.BlueDark;

View File

@ -9,13 +9,14 @@ using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Threading;
using osu.Game.Database;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.Direct;
using osu.Game.Overlays.SearchableList;
using osu.Game.Rulesets;
using OpenTK.Graphics;
namespace osu.Game.Overlays
@ -25,7 +26,7 @@ namespace osu.Game.Overlays
private const float panel_padding = 10f;
private APIAccess api;
private RulesetDatabase rulesets;
private RulesetStore rulesets;
private readonly FillFlowContainer resultCountsContainer;
private readonly OsuSpriteText resultCountsText;
@ -160,7 +161,7 @@ namespace osu.Game.Overlays
}
[BackgroundDependencyLoader]
private void load(OsuColour colours, APIAccess api, RulesetDatabase rulesets)
private void load(OsuColour colours, APIAccess api, RulesetStore rulesets)
{
this.api = api;
this.rulesets = rulesets;
@ -169,7 +170,7 @@ namespace osu.Game.Overlays
private void updateResultCounts()
{
resultCountsContainer.FadeTo(ResultAmounts == null ? 0f : 1f, 200, EasingTypes.OutQuint);
resultCountsContainer.FadeTo(ResultAmounts == null ? 0f : 1f, 200, Easing.OutQuint);
if (ResultAmounts == null) return;
resultCountsText.Text = pluralize("Artist", ResultAmounts.Artists) + ", " +

View File

@ -40,7 +40,7 @@ namespace osu.Game.Overlays
AutoSizeAxes = Axes.Y,
Masking = true,
AutoSizeDuration = transition_time,
AutoSizeEasing = EasingTypes.OutQuint,
AutoSizeEasing = Easing.OutQuint,
Children = new Drawable[]
{
settingsSection = new LoginSettings
@ -67,7 +67,7 @@ namespace osu.Game.Overlays
base.PopIn();
settingsSection.Bounding = true;
FadeIn(transition_time, EasingTypes.OutQuint);
this.FadeIn(transition_time, Easing.OutQuint);
InputManager.ChangeFocus(settingsSection);
}
@ -77,7 +77,7 @@ namespace osu.Game.Overlays
base.PopOut();
settingsSection.Bounding = false;
FadeOut(transition_time);
this.FadeOut(transition_time);
}
}
}

View File

@ -194,38 +194,43 @@ namespace osu.Game.Overlays
{
base.PopIn();
FadeIn(200);
this.FadeIn(200);
background.FlashColour(Color4.White.Opacity(0.25f), 400);
getSample.Play();
using (innerSpin.BeginLoopedSequence())
innerSpin.RotateTo(360, 20000);
using (outerSpin.BeginLoopedSequence())
outerSpin.RotateTo(360, 40000);
innerSpin.Spin(20000, RotationDirection.Clockwise);
outerSpin.Spin(40000, RotationDirection.Clockwise);
using (BeginDelayedSequence(200, true))
{
disc.FadeIn(initial_duration);
disc.FadeIn(initial_duration)
.ScaleTo(1f, initial_duration * 2, Easing.OutElastic);
particleContainer.FadeIn(initial_duration);
outerSpin.FadeTo(0.1f, initial_duration * 2);
disc.ScaleTo(1f, initial_duration * 2, EasingTypes.OutElastic);
using (BeginDelayedSequence(initial_duration + 200, true))
{
backgroundStrip.FadeIn(step_duration);
leftStrip.ResizeWidthTo(1f, step_duration, EasingTypes.OutQuint);
rightStrip.ResizeWidthTo(1f, step_duration, EasingTypes.OutQuint);
Schedule(() => { if (drawableMedal.State != DisplayState.Full) drawableMedal.State = DisplayState.Icon; });
leftStrip.ResizeWidthTo(1f, step_duration, Easing.OutQuint);
rightStrip.ResizeWidthTo(1f, step_duration, Easing.OutQuint);
using (BeginDelayedSequence(step_duration, true))
this.Animate().Schedule(() =>
{
Schedule(() => { if (drawableMedal.State != DisplayState.Full) drawableMedal.State = DisplayState.MedalUnlocked; });
using (BeginDelayedSequence(step_duration, true))
Schedule(() => { if (drawableMedal.State != DisplayState.Full) drawableMedal.State = DisplayState.Full; });
}
if (drawableMedal.State != DisplayState.Full)
drawableMedal.State = DisplayState.Icon;
})
.Delay(step_duration).Schedule(() =>
{
if (drawableMedal.State != DisplayState.Full)
drawableMedal.State = DisplayState.MedalUnlocked;
})
.Delay(step_duration).Schedule(() =>
{
if (drawableMedal.State != DisplayState.Full)
drawableMedal.State = DisplayState.Full;
});
}
}
}
@ -233,7 +238,7 @@ namespace osu.Game.Overlays
protected override void PopOut()
{
base.PopOut();
FadeOut(200);
this.FadeOut(200);
}
private void dismiss()
@ -242,7 +247,7 @@ namespace osu.Game.Overlays
{
// if we haven't yet, play out the animation fully
drawableMedal.State = DisplayState.Full;
Flush(true);
FinishTransforms(true);
return;
}
@ -256,7 +261,7 @@ namespace osu.Game.Overlays
{
RelativeSizeAxes = Axes.Both;
Width = 0f;
ColourInfo = ColourInfo.GradientHorizontal(Color4.White.Opacity(start), Color4.White.Opacity(end));
Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(start), Color4.White.Opacity(end));
Masking = true;
Children = new[]
@ -295,8 +300,8 @@ namespace osu.Game.Overlays
Radius = 5,
};
MoveTo(positionForOffset(DISC_SIZE / 2 + 200), 500);
FadeOut(500);
this.MoveTo(positionForOffset(DISC_SIZE / 2 + 200), 500);
this.FadeOut(500);
Expire();
}
}

View File

@ -147,23 +147,26 @@ namespace osu.Game.Overlays.MedalSplash
medalContainer.ScaleTo(0);
break;
case DisplayState.Icon:
medalContainer.ScaleTo(1, duration, EasingTypes.OutElastic);
medalContainer.FadeIn(duration);
medalContainer
.FadeIn(duration)
.ScaleTo(1, duration, Easing.OutElastic);
break;
case DisplayState.MedalUnlocked:
medalContainer.ScaleTo(1);
medalContainer.Show();
medalContainer
.FadeTo(1)
.ScaleTo(1);
ScaleTo(scale_when_unlocked, duration, EasingTypes.OutExpo);
MoveToY(MedalOverlay.DISC_SIZE / 2 - 30, duration, EasingTypes.OutExpo);
this.ScaleTo(scale_when_unlocked, duration, Easing.OutExpo);
this.MoveToY(MedalOverlay.DISC_SIZE / 2 - 30, duration, Easing.OutExpo);
unlocked.FadeInFromZero(duration);
break;
case DisplayState.Full:
medalContainer.ScaleTo(1);
medalContainer.Show();
medalContainer
.FadeTo(1)
.ScaleTo(1);
ScaleTo(scale_when_full, duration, EasingTypes.OutExpo);
MoveToY(MedalOverlay.DISC_SIZE / 2 - 60, duration, EasingTypes.OutExpo);
this.ScaleTo(scale_when_full, duration, Easing.OutExpo);
this.MoveToY(MedalOverlay.DISC_SIZE / 2 - 60, duration, Easing.OutExpo);
name.FadeInFromZero(duration + 100);
description.FadeInFromZero(duration * 2);
break;

View File

@ -35,7 +35,7 @@ namespace osu.Game.Overlays.Mods
public string TooltipText => (SelectedMod?.Description ?? Mods.FirstOrDefault()?.Description) ?? string.Empty;
private const EasingTypes mod_switch_easing = EasingTypes.InOutSine;
private const Easing mod_switch_easing = Easing.InOutSine;
private const double mod_switch_duration = 120;
// A selected index of -1 means not selected.
@ -67,8 +67,8 @@ namespace osu.Game.Overlays.Mods
if (beforeSelected != Selected)
{
iconsContainer.RotateTo(Selected ? 5f : 0f, 300, EasingTypes.OutElastic);
iconsContainer.ScaleTo(Selected ? 1.1f : 1f, 300, EasingTypes.OutElastic);
iconsContainer.RotateTo(Selected ? 5f : 0f, 300, Easing.OutElastic);
iconsContainer.ScaleTo(Selected ? 1.1f : 1f, 300, Easing.OutElastic);
}
if (modBefore != modAfter)
@ -81,11 +81,13 @@ namespace osu.Game.Overlays.Mods
backgroundIcon.Icon = modAfter.Icon;
using (BeginDelayedSequence(mod_switch_duration, true))
{
foregroundIcon.RotateTo(-rotate_angle * direction);
foregroundIcon.RotateTo(0f, mod_switch_duration, mod_switch_easing);
foregroundIcon
.RotateTo(-rotate_angle * direction)
.RotateTo(0f, mod_switch_duration, mod_switch_easing);
backgroundIcon.RotateTo(rotate_angle * direction);
backgroundIcon.RotateTo(0f, mod_switch_duration, mod_switch_easing);
backgroundIcon
.RotateTo(rotate_angle * direction)
.RotateTo(0f, mod_switch_duration, mod_switch_easing);
Schedule(() => displayMod(modAfter));
}

View File

@ -15,8 +15,8 @@ using osu.Game.Rulesets.Mods;
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Database;
using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets;
namespace osu.Game.Overlays.Mods
{
@ -48,7 +48,7 @@ namespace osu.Game.Overlays.Mods
}
[BackgroundDependencyLoader(permitNulls: true)]
private void load(OsuColour colours, OsuGame osu, RulesetDatabase rulesets)
private void load(OsuColour colours, OsuGame osu, RulesetStore rulesets)
{
lowMultiplierColour = colours.Red;
highMultiplierColour = colours.Green;
@ -66,14 +66,14 @@ namespace osu.Game.Overlays.Mods
{
base.PopOut();
rankedMultiplerContainer.MoveToX(rankedMultiplerContainer.DrawSize.X, APPEAR_DURATION, EasingTypes.InSine);
rankedMultiplerContainer.FadeOut(APPEAR_DURATION, EasingTypes.InSine);
rankedMultiplerContainer.MoveToX(rankedMultiplerContainer.DrawSize.X, APPEAR_DURATION, Easing.InSine);
rankedMultiplerContainer.FadeOut(APPEAR_DURATION, Easing.InSine);
foreach (ModSection section in modSectionsContainer.Children)
{
section.ButtonsContainer.TransformSpacingTo(new Vector2(100f, 0f), APPEAR_DURATION, EasingTypes.InSine);
section.ButtonsContainer.MoveToX(100f, APPEAR_DURATION, EasingTypes.InSine);
section.ButtonsContainer.FadeOut(APPEAR_DURATION, EasingTypes.InSine);
section.ButtonsContainer.TransformSpacingTo(new Vector2(100f, 0f), APPEAR_DURATION, Easing.InSine);
section.ButtonsContainer.MoveToX(100f, APPEAR_DURATION, Easing.InSine);
section.ButtonsContainer.FadeOut(APPEAR_DURATION, Easing.InSine);
}
}
@ -81,14 +81,14 @@ namespace osu.Game.Overlays.Mods
{
base.PopIn();
rankedMultiplerContainer.MoveToX(0, ranked_multiplier_duration, EasingTypes.OutQuint);
rankedMultiplerContainer.FadeIn(ranked_multiplier_duration, EasingTypes.OutQuint);
rankedMultiplerContainer.MoveToX(0, ranked_multiplier_duration, Easing.OutQuint);
rankedMultiplerContainer.FadeIn(ranked_multiplier_duration, Easing.OutQuint);
foreach (ModSection section in modSectionsContainer.Children)
{
section.ButtonsContainer.TransformSpacingTo(new Vector2(50f, 0f), button_duration, EasingTypes.OutQuint);
section.ButtonsContainer.MoveToX(0, button_duration, EasingTypes.OutQuint);
section.ButtonsContainer.FadeIn(button_duration, EasingTypes.OutQuint);
section.ButtonsContainer.TransformSpacingTo(new Vector2(50f, 0f), button_duration, Easing.OutQuint);
section.ButtonsContainer.MoveToX(0, button_duration, Easing.OutQuint);
section.ButtonsContainer.FadeIn(button_duration, Easing.OutQuint);
}
}

View File

@ -9,7 +9,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Database;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Music
if (value == selected) return;
selected = value;
Flush(true);
FinishTransforms(true);
foreach (SpriteText s in titleSprites)
s.FadeColour(Selected ? hoverColour : Color4.White, fade_duration);
}
@ -145,7 +145,7 @@ namespace osu.Game.Overlays.Music
matching = value;
FadeTo(matching ? 1 : 0, 200);
this.FadeTo(matching ? 1 : 0, 200);
}
}
}

View File

@ -6,7 +6,7 @@ using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Database;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays.Music
@ -73,6 +73,17 @@ namespace osu.Game.Overlays.Music
};
}
public void AddBeatmapSet(BeatmapSetInfo beatmapSet)
{
items.Add(new PlaylistItem(beatmapSet) { OnSelect = itemSelected });
}
public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet)
{
PlaylistItem itemToRemove = items.Children.FirstOrDefault(item => item.BeatmapSetInfo.ID == beatmapSet.ID);
if (itemToRemove != null) items.Remove(itemToRemove);
}
private class ItemSearchContainer : FillFlowContainer<PlaylistItem>, IHasFilterableChildren
{
public string[] FilterTerms => new string[] { };
@ -90,7 +101,7 @@ namespace osu.Game.Overlays.Music
public ItemSearchContainer()
{
LayoutDuration = 200;
LayoutEasing = EasingTypes.OutQuint;
LayoutEasing = Easing.OutQuint;
}
}
}

View File

@ -3,9 +3,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
using osu.Framework.Configuration;
using osu.Framework.Extensions;
using osu.Framework.Extensions.Color4Extensions;
@ -14,10 +12,11 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Graphics;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Input;
using osu.Framework.Graphics.Shapes;
namespace osu.Game.Overlays.Music
{
@ -30,8 +29,7 @@ namespace osu.Game.Overlays.Music
private FilterControl filter;
private PlaylistList list;
private TrackManager trackManager;
private BeatmapDatabase beatmaps;
private BeatmapManager beatmaps;
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
@ -39,11 +37,10 @@ namespace osu.Game.Overlays.Music
private InputManager inputManager;
[BackgroundDependencyLoader]
private void load(OsuGameBase game, BeatmapDatabase beatmaps, OsuColour colours, UserInputManager inputManager)
private void load(OsuGameBase game, BeatmapManager beatmaps, OsuColour colours, UserInputManager inputManager)
{
this.inputManager = inputManager;
this.beatmaps = beatmaps;
trackManager = game.Audio.Track;
Children = new Drawable[]
{
@ -83,7 +80,11 @@ namespace osu.Game.Overlays.Music
},
};
list.BeatmapSets = BeatmapSets = beatmaps.GetAllWithChildren<BeatmapSetInfo>(b => !b.DeletePending).ToList();
beatmaps.BeatmapSetAdded += s => Schedule(() => list.AddBeatmapSet(s));
beatmaps.BeatmapSetRemoved += s => Schedule(() => list.RemoveBeatmapSet(s));
list.BeatmapSets = BeatmapSets = beatmaps.GetAllUsableBeatmapSets();
beatmapBacking.BindTo(game.Beatmap);
@ -106,16 +107,16 @@ namespace osu.Game.Overlays.Music
filter.Search.HoldFocus = true;
Schedule(() => inputManager.ChangeFocus(filter.Search));
ResizeTo(new Vector2(1, playlist_height), transition_duration, EasingTypes.OutQuint);
FadeIn(transition_duration, EasingTypes.OutQuint);
this.ResizeTo(new Vector2(1, playlist_height), transition_duration, Easing.OutQuint);
this.FadeIn(transition_duration, Easing.OutQuint);
}
protected override void PopOut()
{
filter.Search.HoldFocus = false;
ResizeTo(new Vector2(1, 0), transition_duration, EasingTypes.OutQuint);
FadeOut(transition_duration);
this.ResizeTo(new Vector2(1, 0), transition_duration, Easing.OutQuint);
this.FadeOut(transition_duration);
}
private void itemSelected(BeatmapSetInfo set)
@ -154,13 +155,7 @@ namespace osu.Game.Overlays.Music
private void playSpecified(BeatmapInfo info)
{
beatmapBacking.Value = beatmaps.GetWorkingBeatmap(info, beatmapBacking);
Task.Run(() =>
{
var track = beatmapBacking.Value.Track;
trackManager.SetExclusive(track);
track.Start();
}).ContinueWith(task => Schedule(task.ThrowIfFaulted), TaskContinuationOptions.OnlyOnFaulted);
beatmapBacking.Value.Track.Start();
}
}

View File

@ -19,7 +19,6 @@ using osu.Framework.Input;
using osu.Framework.Localisation;
using osu.Framework.Threading;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays.Music;
@ -84,7 +83,7 @@ namespace osu.Game.Overlays
protected override bool OnDragEnd(InputState state)
{
dragContainer.MoveTo(Vector2.Zero, 800, EasingTypes.OutElastic);
dragContainer.MoveTo(Vector2.Zero, 800, Easing.OutElastic);
return base.OnDragEnd(state);
}
@ -206,7 +205,7 @@ namespace osu.Game.Overlays
beatmapBacking.BindTo(game.Beatmap);
playlist.StateChanged += (c, s) => playlistButton.FadeColour(s == Visibility.Visible ? colours.Yellow : Color4.White, 200, EasingTypes.OutQuint);
playlist.StateChanged += (c, s) => playlistButton.FadeColour(s == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint);
}
protected override void LoadComplete()
@ -356,13 +355,13 @@ namespace osu.Game.Overlays
{
case TransformDirection.Next:
d.Position = new Vector2(400, 0);
d.MoveToX(0, 500, EasingTypes.OutCubic);
currentBackground.MoveToX(-400, 500, EasingTypes.OutCubic);
d.MoveToX(0, 500, Easing.OutCubic);
currentBackground.MoveToX(-400, 500, Easing.OutCubic);
break;
case TransformDirection.Prev:
d.Position = new Vector2(-400, 0);
d.MoveToX(0, 500, EasingTypes.OutCubic);
currentBackground.MoveToX(400, 500, EasingTypes.OutCubic);
d.MoveToX(0, 500, Easing.OutCubic);
currentBackground.MoveToX(400, 500, Easing.OutCubic);
break;
}
currentBackground.Expire();
@ -379,16 +378,16 @@ namespace osu.Game.Overlays
{
base.PopIn();
FadeIn(transition_length, EasingTypes.OutQuint);
dragContainer.ScaleTo(1, transition_length, EasingTypes.OutElastic);
this.FadeIn(transition_length, Easing.OutQuint);
dragContainer.ScaleTo(1, transition_length, Easing.OutElastic);
}
protected override void PopOut()
{
base.PopOut();
FadeOut(transition_length, EasingTypes.OutQuint);
dragContainer.ScaleTo(0.9f, transition_length, EasingTypes.OutQuint);
this.FadeOut(transition_length, Easing.OutQuint);
dragContainer.ScaleTo(0.9f, transition_length, Easing.OutQuint);
}
private enum TransformDirection

View File

@ -13,7 +13,7 @@ using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays
{
public class NotificationManager : OsuFocusedOverlayContainer
public class NotificationOverlay : OsuFocusedOverlayContainer
{
private const float width = 320;
@ -28,6 +28,8 @@ namespace osu.Game.Overlays
Width = width;
RelativeSizeAxes = Axes.Y;
AlwaysPresent = true;
Children = new Drawable[]
{
new Box
@ -72,26 +74,29 @@ namespace osu.Game.Overlays
public void Post(Notification notification)
{
State = Visibility.Visible;
Schedule(() =>
{
State = Visibility.Visible;
++runningDepth;
notification.Depth = notification.DisplayOnTop ? runningDepth : -runningDepth;
++runningDepth;
notification.Depth = notification.DisplayOnTop ? runningDepth : -runningDepth;
var hasCompletionTarget = notification as IHasCompletionTarget;
if (hasCompletionTarget != null)
hasCompletionTarget.CompletionTarget = Post;
var hasCompletionTarget = notification as IHasCompletionTarget;
if (hasCompletionTarget != null)
hasCompletionTarget.CompletionTarget = Post;
var ourType = notification.GetType();
sections.Children.FirstOrDefault(s => s.AcceptTypes.Any(accept => accept.IsAssignableFrom(ourType)))?.Add(notification);
var ourType = notification.GetType();
sections.Children.FirstOrDefault(s => s.AcceptTypes.Any(accept => accept.IsAssignableFrom(ourType)))?.Add(notification);
});
}
protected override void PopIn()
{
base.PopIn();
scrollContainer.MoveToX(0, TRANSITION_LENGTH, EasingTypes.OutQuint);
MoveToX(0, TRANSITION_LENGTH, EasingTypes.OutQuint);
FadeTo(1, TRANSITION_LENGTH / 2);
scrollContainer.MoveToX(0, TRANSITION_LENGTH, Easing.OutQuint);
this.MoveToX(0, TRANSITION_LENGTH, Easing.OutQuint);
this.FadeTo(1, TRANSITION_LENGTH / 2);
}
private void markAllRead()
@ -105,8 +110,8 @@ namespace osu.Game.Overlays
markAllRead();
MoveToX(width, TRANSITION_LENGTH, EasingTypes.OutQuint);
FadeTo(0, TRANSITION_LENGTH / 2);
this.MoveToX(width, TRANSITION_LENGTH, Easing.OutQuint);
this.FadeTo(0, TRANSITION_LENGTH / 2);
}
}
}
}

View File

@ -63,6 +63,8 @@ namespace osu.Game.Overlays.Notifications
Masking = true,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
AutoSizeDuration = 400,
AutoSizeEasing = Easing.OutQuint,
Children = new Drawable[]
{
new Box
@ -74,7 +76,7 @@ namespace osu.Game.Overlays.Notifications
{
RelativeSizeAxes = Axes.X,
Padding = new MarginPadding(5),
Height = 60,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
IconContent = new Container
@ -135,9 +137,9 @@ namespace osu.Game.Overlays.Notifications
protected override void LoadComplete()
{
base.LoadComplete();
FadeInFromZero(200);
this.FadeInFromZero(200);
NotificationContent.MoveToX(DrawSize.X);
NotificationContent.MoveToX(0, 500, EasingTypes.OutQuint);
NotificationContent.MoveToX(0, 500, Easing.OutQuint);
}
private bool wasClosed;
@ -148,7 +150,7 @@ namespace osu.Game.Overlays.Notifications
wasClosed = true;
Closed?.Invoke();
FadeOut(100);
this.FadeOut(100);
Expire();
}
@ -181,13 +183,13 @@ namespace osu.Game.Overlays.Notifications
protected override bool OnHover(InputState state)
{
FadeColour(hoverColour, 200);
this.FadeColour(hoverColour, 200);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
FadeColour(OsuColour.Gray(0.2f), 200);
this.FadeColour(OsuColour.Gray(0.2f), 200);
base.OnHoverLost(state);
}
}
@ -212,12 +214,9 @@ namespace osu.Game.Overlays.Notifications
if (pulsate)
{
const float length = 1000;
using (pulsateLayer.BeginLoopedSequence(length / 2))
{
pulsateLayer.FadeTo(0.4f, length, EasingTypes.In);
using (pulsateLayer.BeginDelayedSequence(length))
pulsateLayer.FadeTo(1, length, EasingTypes.Out);
}
pulsateLayer.Loop(length / 2,
p => p.FadeTo(0.4f, length, Easing.In).Then().FadeTo(1, length, Easing.Out)
);
}
}
}

View File

@ -114,7 +114,7 @@ namespace osu.Game.Overlays.Notifications
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
LayoutDuration = 150,
LayoutEasing = EasingTypes.OutQuart,
LayoutEasing = Easing.OutQuart,
Spacing = new Vector2(3),
}
});

View File

@ -18,7 +18,7 @@ namespace osu.Game.Overlays.Notifications
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
IconBackgound.ColourInfo = ColourInfo.GradientVertical(colours.GreenDark, colours.GreenLight);
IconBackgound.Colour = ColourInfo.GradientVertical(colours.GreenDark, colours.GreenLight);
}
}
}

View File

@ -6,9 +6,7 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using OpenTK;
using OpenTK.Graphics;
@ -18,10 +16,9 @@ namespace osu.Game.Overlays.Notifications
{
public string Text
{
get { return textDrawable.Text; }
set
{
textDrawable.Text = value;
Schedule(() => textDrawable.Text = value);
}
}
@ -77,11 +74,8 @@ namespace osu.Game.Overlays.Notifications
switch (state)
{
case ProgressNotificationState.Completed:
NotificationContent.MoveToY(-DrawSize.Y / 2, 200, EasingTypes.OutQuint);
FadeTo(0.01f, 200); //don't completely fade out or our scheduled task won't run.
Delay(100);
Schedule(Completed);
NotificationContent.MoveToY(-DrawSize.Y / 2, 200, Easing.OutQuint);
this.FadeOut(200).Finally(d => Completed());
break;
}
}
@ -93,7 +87,7 @@ namespace osu.Game.Overlays.Notifications
protected virtual Notification CreateCompletionNotification() => new ProgressCompletionNotification
{
Activated = CompletionClickAction,
Text = $"Task \"{Text}\" has completed!"
Text = "Task has completed!"
};
protected virtual void Completed()
@ -109,7 +103,7 @@ namespace osu.Game.Overlays.Notifications
private Color4 colourActive;
private Color4 colourCancelled;
private readonly SpriteText textDrawable;
private readonly TextFlowContainer textDrawable;
public ProgressNotification()
{
@ -118,9 +112,11 @@ namespace osu.Game.Overlays.Notifications
RelativeSizeAxes = Axes.Both,
});
Content.Add(textDrawable = new OsuSpriteText
Content.Add(textDrawable = new TextFlowContainer(t =>
{
t.TextSize = 16;
})
{
TextSize = 16,
Colour = OsuColour.Gray(128),
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
@ -134,6 +130,9 @@ namespace osu.Game.Overlays.Notifications
});
State = ProgressNotificationState.Queued;
// don't close on click by default.
Activated = () => false;
}
[BackgroundDependencyLoader]
@ -170,7 +169,7 @@ namespace osu.Game.Overlays.Notifications
private class ProgressBar : Container
{
private Box box;
private readonly Box box;
private Color4 colourActive;
private Color4 colourInactive;
@ -184,7 +183,7 @@ namespace osu.Game.Overlays.Notifications
if (progress == value) return;
progress = value;
box.ResizeTo(new Vector2(progress, 1), 100, EasingTypes.OutQuad);
box.ResizeTo(new Vector2(progress, 1), 100, Easing.OutQuad);
}
}
@ -196,19 +195,12 @@ namespace osu.Game.Overlays.Notifications
set
{
active = value;
FadeColour(active ? colourActive : colourInactive, 100);
this.FadeColour(active ? colourActive : colourInactive, 100);
}
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
public ProgressBar()
{
colourActive = colours.Blue;
Colour = colourInactive = OsuColour.Gray(0.5f);
Height = 5;
Children = new[]
{
box = new Box
@ -218,6 +210,15 @@ namespace osu.Game.Overlays.Notifications
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
colourActive = colours.Blue;
Colour = colourInactive = OsuColour.Gray(0.5f);
Height = 5;
}
}
}

View File

@ -47,7 +47,7 @@ namespace osu.Game.Overlays.Notifications
IconBackgound = new Box
{
RelativeSizeAxes = Axes.Both,
ColourInfo = ColourInfo.GradientVertical(OsuColour.Gray(0.2f), OsuColour.Gray(0.6f))
Colour = ColourInfo.GradientVertical(OsuColour.Gray(0.2f), OsuColour.Gray(0.6f))
},
iconDrawable = new TextAwesome
{

View File

@ -154,14 +154,13 @@ namespace osu.Game.Overlays
textLine2.Text = settingValue;
textLine3.Text = shortcut.ToUpper();
box.FadeIn(500, EasingTypes.OutQuint);
box.ResizeHeightTo(height, 500, EasingTypes.OutQuint);
using (box.BeginDelayedSequence(500))
{
box.FadeOutFromOne(1500, EasingTypes.InQuint);
box.ResizeHeightTo(height_contracted, 1500, EasingTypes.InQuint);
}
box.Animate(
b => b.FadeIn(500, Easing.OutQuint),
b => b.ResizeHeightTo(height, 500, Easing.OutQuint)
).Then(
b => b.FadeOutFromOne(1500, Easing.InQuint),
b => b.ResizeHeightTo(height_contracted, 1500, Easing.InQuint)
);
int optionCount = 0;
int selectedOption = -1;
@ -232,13 +231,13 @@ namespace osu.Game.Overlays
{
if (glowing)
{
fill.FadeColour(glowingColour, transition_speed, EasingTypes.OutQuint);
FadeEdgeEffectTo(glow_strength, transition_speed, EasingTypes.OutQuint);
fill.FadeColour(glowingColour, transition_speed, Easing.OutQuint);
FadeEdgeEffectTo(glow_strength, transition_speed, Easing.OutQuint);
}
else
{
FadeEdgeEffectTo(0, transition_speed, EasingTypes.OutQuint);
fill.FadeColour(idleColour, transition_speed, EasingTypes.OutQuint);
FadeEdgeEffectTo(0, transition_speed, Easing.OutQuint);
fill.FadeColour(idleColour, transition_speed, Easing.OutQuint);
}
}
@ -261,7 +260,7 @@ namespace osu.Game.Overlays
};
updateGlow();
Flush(true);
FinishTransforms(true);
}
}
}

Some files were not shown because too many files have changed in this diff Show More