diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 0f805990b9..0aa1c62d04 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -136,18 +136,19 @@ namespace osu.Game.Skinning protected override string ComputeHash(SkinInfo item, ArchiveReader reader = null) { - // we need to populate early to create a hash based off skin.ini contents - if (item.Name?.Contains(".osk", StringComparison.OrdinalIgnoreCase) == true) - populateMetadata(item, GetSkin(item)); + var instance = GetSkin(item); - if (item.Creator != null && item.Creator != unknown_creator_string) + // in the case the skin has a skin.ini file, we are going to create a hash based on that. + // we don't want to do this in the case we don't have a skin.ini, as it would match only on the filename portion, + // causing potentially unique skin imports to be considered as a duplicate. + if (!string.IsNullOrEmpty(instance.Configuration.SkinInfo.Name)) { - // this is the optimal way to hash legacy skins, but will need to be reconsidered when we move forward with skin implementation. - // likely, the skin should expose a real version (ie. the version of the skin, not the skin.ini version it's targeting). + // we need to populate early to create a hash based off skin.ini contents + populateMetadata(item, instance, reader?.Name); + return item.ToString().ComputeSHA2Hash(); } - // if there was no creator, the ToString above would give the filename, which alone isn't really enough to base any decisions on. return base.ComputeHash(item, reader); } @@ -157,13 +158,12 @@ namespace osu.Game.Skinning model.InstantiationInfo ??= instance.GetType().GetInvariantInstantiationInfo(); - if (model.Name?.Contains(".osk", StringComparison.OrdinalIgnoreCase) == true) - populateMetadata(model, instance); + populateMetadata(model, instance, archive?.Name); return Task.CompletedTask; } - private void populateMetadata(SkinInfo item, Skin instance) + private void populateMetadata(SkinInfo item, Skin instance, string archiveName) { if (!string.IsNullOrEmpty(instance.Configuration.SkinInfo.Name)) { @@ -175,6 +175,13 @@ namespace osu.Game.Skinning item.Name = item.Name.Replace(".osk", "", StringComparison.OrdinalIgnoreCase); item.Creator ??= unknown_creator_string; } + + // generally when importing from a folder, the ".osk" extension will not be present. + // if we ever need a more reliable method of determining this, the type of `ArchiveReader` can be checked. + bool isArchiveImport = archiveName?.Contains(".osk", StringComparison.OrdinalIgnoreCase) == true; + + if (archiveName != null && !isArchiveImport && archiveName != item.Name) + item.Name = $"{item.Name} ({archiveName})"; } ///