2021-11-09 20:34:56 +08:00
|
|
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
|
|
// See the LICENCE file in the repository root for full licence text.
|
|
|
|
|
2021-11-19 15:07:55 +08:00
|
|
|
using System.IO;
|
2021-11-25 15:33:35 +08:00
|
|
|
using System.Linq;
|
2021-11-09 20:34:56 +08:00
|
|
|
using osu.Game.Beatmaps;
|
2021-11-15 13:34:50 +08:00
|
|
|
using osu.Game.Database;
|
2021-11-19 15:07:55 +08:00
|
|
|
using osu.Game.IO;
|
2021-11-16 11:44:20 +08:00
|
|
|
using osu.Game.Online.API.Requests.Responses;
|
2021-11-09 20:34:56 +08:00
|
|
|
using osu.Game.Rulesets;
|
|
|
|
using osu.Game.Scoring;
|
|
|
|
using osu.Game.Users;
|
|
|
|
|
2021-11-15 13:38:01 +08:00
|
|
|
#nullable enable
|
|
|
|
|
2021-11-09 20:34:56 +08:00
|
|
|
namespace osu.Game.Extensions
|
|
|
|
{
|
|
|
|
public static class ModelExtensions
|
|
|
|
{
|
2021-11-19 15:07:55 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Get the relative path in osu! storage for this file.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="fileInfo">The file info.</param>
|
|
|
|
/// <returns>A relative file path.</returns>
|
|
|
|
public static string GetStoragePath(this IFileInfo fileInfo) => Path.Combine(fileInfo.Hash.Remove(1), fileInfo.Hash.Remove(2), fileInfo.Hash);
|
|
|
|
|
2021-11-09 20:34:56 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Returns a user-facing string representing the <paramref name="model"/>.
|
|
|
|
/// </summary>
|
|
|
|
/// <remarks>
|
|
|
|
/// <para>
|
|
|
|
/// Non-interface types without special handling will fall back to <see cref="object.ToString()"/>.
|
|
|
|
/// </para>
|
|
|
|
/// <para>
|
|
|
|
/// Warning: This method is _purposefully_ not called <c>GetDisplayTitle()</c> like the others, because otherwise
|
|
|
|
/// extension method type inference rules cause this method to call itself and cause a stack overflow.
|
|
|
|
/// </para>
|
|
|
|
/// </remarks>
|
2021-11-15 13:38:01 +08:00
|
|
|
public static string GetDisplayString(this object? model)
|
2021-11-09 20:34:56 +08:00
|
|
|
{
|
2021-11-15 13:38:01 +08:00
|
|
|
string? result = null;
|
2021-11-09 20:34:56 +08:00
|
|
|
|
|
|
|
switch (model)
|
|
|
|
{
|
|
|
|
case IBeatmapSetInfo beatmapSetInfo:
|
2021-11-24 14:01:45 +08:00
|
|
|
result = beatmapSetInfo.Metadata.GetDisplayTitle();
|
2021-11-09 20:34:56 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case IBeatmapInfo beatmapInfo:
|
|
|
|
result = beatmapInfo.GetDisplayTitle();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IBeatmapMetadataInfo metadataInfo:
|
|
|
|
result = metadataInfo.GetDisplayTitle();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IScoreInfo scoreInfo:
|
|
|
|
result = scoreInfo.GetDisplayTitle();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IRulesetInfo rulesetInfo:
|
|
|
|
result = rulesetInfo.Name;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IUser user:
|
|
|
|
result = user.Username;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// fallback in case none of the above happens to match.
|
2021-11-12 14:25:59 +08:00
|
|
|
result ??= model?.ToString() ?? @"null";
|
2021-11-09 20:34:56 +08:00
|
|
|
return result;
|
|
|
|
}
|
2021-11-15 13:34:50 +08:00
|
|
|
|
|
|
|
/// <summary>
|
2021-11-16 11:37:47 +08:00
|
|
|
/// Check whether the online ID of two <see cref="IBeatmapSetInfo"/>s match.
|
2021-11-15 13:34:50 +08:00
|
|
|
/// </summary>
|
|
|
|
/// <param name="instance">The instance to compare.</param>
|
|
|
|
/// <param name="other">The other instance to compare against.</param>
|
|
|
|
/// <returns>Whether online IDs match. If either instance is missing an online ID, this will return false.</returns>
|
2021-11-16 11:37:47 +08:00
|
|
|
public static bool MatchesOnlineID(this IBeatmapSetInfo? instance, IBeatmapSetInfo? other) => matchesOnlineID(instance, other);
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Check whether the online ID of two <see cref="IBeatmapInfo"/>s match.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="instance">The instance to compare.</param>
|
|
|
|
/// <param name="other">The other instance to compare against.</param>
|
|
|
|
/// <returns>Whether online IDs match. If either instance is missing an online ID, this will return false.</returns>
|
|
|
|
public static bool MatchesOnlineID(this IBeatmapInfo? instance, IBeatmapInfo? other) => matchesOnlineID(instance, other);
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Check whether the online ID of two <see cref="IRulesetInfo"/>s match.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="instance">The instance to compare.</param>
|
|
|
|
/// <param name="other">The other instance to compare against.</param>
|
|
|
|
/// <returns>Whether online IDs match. If either instance is missing an online ID, this will return false.</returns>
|
|
|
|
public static bool MatchesOnlineID(this IRulesetInfo? instance, IRulesetInfo? other) => matchesOnlineID(instance, other);
|
|
|
|
|
2021-11-16 11:44:20 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Check whether the online ID of two <see cref="APIUser"/>s match.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="instance">The instance to compare.</param>
|
|
|
|
/// <param name="other">The other instance to compare against.</param>
|
|
|
|
/// <returns>Whether online IDs match. If either instance is missing an online ID, this will return false.</returns>
|
|
|
|
public static bool MatchesOnlineID(this APIUser? instance, APIUser? other) => matchesOnlineID(instance, other);
|
|
|
|
|
2021-12-10 17:32:06 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Check whether the online ID of two <see cref="IScoreInfo"/>s match.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="instance">The instance to compare.</param>
|
|
|
|
/// <param name="other">The other instance to compare against.</param>
|
|
|
|
/// <returns>Whether online IDs match. If either instance is missing an online ID, this will return false.</returns>
|
|
|
|
public static bool MatchesOnlineID(this IScoreInfo? instance, IScoreInfo? other) => matchesOnlineID(instance, other);
|
|
|
|
|
2021-11-16 11:37:47 +08:00
|
|
|
private static bool matchesOnlineID(this IHasOnlineID<long>? instance, IHasOnlineID<long>? other)
|
2021-11-15 13:34:50 +08:00
|
|
|
{
|
2021-11-15 13:38:01 +08:00
|
|
|
if (instance == null || other == null)
|
|
|
|
return false;
|
|
|
|
|
2021-11-15 13:34:50 +08:00
|
|
|
if (instance.OnlineID < 0 || other.OnlineID < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return instance.OnlineID.Equals(other.OnlineID);
|
|
|
|
}
|
|
|
|
|
2021-11-16 11:37:47 +08:00
|
|
|
private static bool matchesOnlineID(this IHasOnlineID<int>? instance, IHasOnlineID<int>? other)
|
2021-11-15 13:34:50 +08:00
|
|
|
{
|
2021-11-15 13:38:01 +08:00
|
|
|
if (instance == null || other == null)
|
|
|
|
return false;
|
|
|
|
|
2021-11-15 13:34:50 +08:00
|
|
|
if (instance.OnlineID < 0 || other.OnlineID < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return instance.OnlineID.Equals(other.OnlineID);
|
|
|
|
}
|
2021-11-25 15:33:35 +08:00
|
|
|
|
|
|
|
private static readonly char[] invalid_filename_characters = Path.GetInvalidFileNameChars()
|
|
|
|
// Backslash is added to avoid issues when exporting to zip.
|
|
|
|
// See SharpCompress filename normalisation https://github.com/adamhathcock/sharpcompress/blob/a1e7c0068db814c9aa78d86a94ccd1c761af74bd/src/SharpCompress/Writers/Zip/ZipWriter.cs#L143.
|
|
|
|
.Append('\\')
|
|
|
|
.ToArray();
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Get a valid filename for use inside a zip file. Avoids backslashes being incorrectly converted to directories.
|
|
|
|
/// </summary>
|
|
|
|
public static string GetValidArchiveContentFilename(this string filename)
|
|
|
|
{
|
|
|
|
foreach (char c in invalid_filename_characters)
|
|
|
|
filename = filename.Replace(c, '_');
|
|
|
|
return filename;
|
|
|
|
}
|
2021-11-09 20:34:56 +08:00
|
|
|
}
|
|
|
|
}
|