Files
bansonic_beta_main/Assets/scripts/Data/HeroSkinResolver.cs
T
2026-06-30 21:21:30 +08:00

343 lines
10 KiB
C#

using System;
using System.Collections.Generic;
using Spine.Unity;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
public sealed class HeroSkinResolvedData
{
public string skinId;
public int heroId;
public string skinName;
public string ally_heroDesignation;
public bool isBaseSkin;
public bool isDefaultSkin;
public bool unlockedByDefault;
public string sourceDlcId;
public int sortOrder;
public Sprite ally_heroImage;
public Sprite ally_heroProfile;
public Sprite ally_heroSelectIcon;
public Sprite ally_heroIcon;
public Sprite ally_heroPoster;
public Sprite ally_hero_HD_image;
public Sprite ally_hero_squareProfile;
public SkeletonDataAsset ally_heroSpineData;
public Color ally_heroThemeColor;
public string skinDescription;
public AllyHero_SO ownerHero;
public HeroSkinSO sourceSkin;
}
public static class HeroSkinResolver
{
private const string RuntimeResourcesFolder = "so/heroSkins";
private const string EditorSearchFolder = "Assets/Resources/so/heroSkins";
private static HeroSkinSO[] cachedAllSkins;
private static readonly Dictionary<int, List<HeroSkinSO>> CachedByHeroId = new Dictionary<int, List<HeroSkinSO>>();
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void ResetStaticState()
{
cachedAllSkins = null;
CachedByHeroId.Clear();
}
public static void InvalidateCache()
{
cachedAllSkins = null;
CachedByHeroId.Clear();
}
public static List<HeroSkinResolvedData> GetSkinSet(AllyHero_SO hero, bool includeBaseSkin = true)
{
List<HeroSkinResolvedData> result = new List<HeroSkinResolvedData>();
if (hero == null)
{
return result;
}
if (includeBaseSkin)
{
result.Add(BuildBaseSkin(hero));
}
List<HeroSkinSO> extras = GetExtraSkinsForHero(hero.ally_heroID);
for (int i = 0; i < extras.Count; i++)
{
HeroSkinSO extraSkin = extras[i];
if (extraSkin == null)
{
continue;
}
result.Add(BuildExtraSkin(hero, extraSkin));
}
result.Sort(CompareResolvedSkin);
return result;
}
public static HeroSkinResolvedData GetSkinById(AllyHero_SO hero, string skinId, bool fallbackToBase = true)
{
if (hero == null)
{
return null;
}
List<HeroSkinResolvedData> skinSet = GetSkinSet(hero, true);
string safeSkinId = string.IsNullOrWhiteSpace(skinId) ? string.Empty : skinId.Trim();
for (int i = 0; i < skinSet.Count; i++)
{
HeroSkinResolvedData skin = skinSet[i];
if (skin == null)
{
continue;
}
if (string.Equals(skin.skinId, safeSkinId, StringComparison.Ordinal))
{
return skin;
}
}
return fallbackToBase ? BuildBaseSkin(hero) : null;
}
public static HeroSkinResolvedData GetAccessibleSkinById(AllyHero_SO hero, string skinId, bool fallbackToBase = true)
{
HeroSkinResolvedData resolved = GetSkinById(hero, skinId, fallbackToBase);
if (DlcContentAccess.IsSkinAccessible(resolved))
{
return resolved;
}
return fallbackToBase ? BuildBaseSkin(hero) : null;
}
public static HeroSkinResolvedData BuildBaseSkin(AllyHero_SO hero)
{
if (hero == null)
{
return null;
}
return new HeroSkinResolvedData
{
skinId = BuildBaseSkinId(hero.ally_heroID),
heroId = hero.ally_heroID,
skinName = hero.ally_heroName,
ally_heroDesignation = hero.ally_heroDesignation,
isBaseSkin = true,
isDefaultSkin = true,
unlockedByDefault = true,
sourceDlcId = string.Empty,
sortOrder = int.MinValue,
ally_heroImage = hero.ally_heroImage,
ally_heroProfile = hero.ally_heroProfile,
ally_heroSelectIcon = hero.ally_heroSelectIcon,
ally_heroIcon = hero.ally_heroIcon,
ally_heroPoster = hero.ally_heroPoster,
ally_hero_HD_image = hero.ally_hero_HD_image,
ally_hero_squareProfile = hero.ally_hero_squareProfile,
ally_heroSpineData = hero.ally_heroSpineData,
ally_heroThemeColor = hero.ally_heroThemeColor,
skinDescription = hero.ally_heroDescription,
ownerHero = hero,
sourceSkin = null
};
}
public static string BuildBaseSkinId(int heroId)
{
return "hero_" + heroId + "_base";
}
public static List<HeroSkinSO> GetExtraSkinsForHero(int heroId)
{
EnsureCacheBuilt();
if (heroId <= 0)
{
return new List<HeroSkinSO>();
}
if (!CachedByHeroId.TryGetValue(heroId, out List<HeroSkinSO> list) || list == null)
{
return new List<HeroSkinSO>();
}
return new List<HeroSkinSO>(list);
}
public static HeroSkinSO[] LoadAllHeroSkinAssets()
{
EnsureCacheBuilt();
return cachedAllSkins ?? Array.Empty<HeroSkinSO>();
}
private static HeroSkinResolvedData BuildExtraSkin(AllyHero_SO hero, HeroSkinSO skin)
{
return new HeroSkinResolvedData
{
skinId = skin.GetResolvedSkinId(),
heroId = hero != null ? hero.ally_heroID : skin.heroId,
skinName = string.IsNullOrWhiteSpace(skin.skinName) ? skin.name : skin.skinName,
ally_heroDesignation = string.IsNullOrWhiteSpace(skin.ally_heroDesignation) && hero != null ? hero.ally_heroDesignation : skin.ally_heroDesignation,
isBaseSkin = false,
isDefaultSkin = skin.isDefaultSkin,
unlockedByDefault = skin.unlockedByDefault,
sourceDlcId = skin.sourceDlcId ?? string.Empty,
sortOrder = skin.sortOrder,
ally_heroImage = skin.ally_heroImage,
ally_heroProfile = skin.ally_heroProfile,
ally_heroSelectIcon = skin.ally_heroSelectIcon,
ally_heroIcon = skin.ally_heroIcon,
ally_heroPoster = skin.ally_heroPoster,
ally_hero_HD_image = skin.ally_hero_HD_image,
ally_hero_squareProfile = skin.ally_hero_squareProfile,
ally_heroSpineData = skin.ally_heroSpineData,
ally_heroThemeColor = skin.ally_heroThemeColor,
skinDescription = skin.skinDescription,
ownerHero = hero,
sourceSkin = skin
};
}
private static int CompareResolvedSkin(HeroSkinResolvedData left, HeroSkinResolvedData right)
{
if (ReferenceEquals(left, right))
{
return 0;
}
if (left == null)
{
return 1;
}
if (right == null)
{
return -1;
}
if (left.isBaseSkin != right.isBaseSkin)
{
return left.isBaseSkin ? -1 : 1;
}
int sortCompare = left.sortOrder.CompareTo(right.sortOrder);
if (sortCompare != 0)
{
return sortCompare;
}
return string.CompareOrdinal(left.skinId ?? string.Empty, right.skinId ?? string.Empty);
}
private static void EnsureCacheBuilt()
{
if (cachedAllSkins != null)
{
return;
}
cachedAllSkins = LoadAllHeroSkinsInternal();
CachedByHeroId.Clear();
for (int i = 0; i < cachedAllSkins.Length; i++)
{
HeroSkinSO skin = cachedAllSkins[i];
if (skin == null || skin.heroId <= 0)
{
continue;
}
if (!CachedByHeroId.TryGetValue(skin.heroId, out List<HeroSkinSO> list) || list == null)
{
list = new List<HeroSkinSO>();
CachedByHeroId[skin.heroId] = list;
}
list.Add(skin);
}
foreach (KeyValuePair<int, List<HeroSkinSO>> pair in CachedByHeroId)
{
pair.Value.Sort(CompareSkinAsset);
}
}
private static int CompareSkinAsset(HeroSkinSO left, HeroSkinSO right)
{
if (ReferenceEquals(left, right))
{
return 0;
}
if (left == null)
{
return 1;
}
if (right == null)
{
return -1;
}
int sortCompare = left.sortOrder.CompareTo(right.sortOrder);
if (sortCompare != 0)
{
return sortCompare;
}
return string.CompareOrdinal(left.GetResolvedSkinId(), right.GetResolvedSkinId());
}
private static HeroSkinSO[] LoadAllHeroSkinsInternal()
{
#if UNITY_EDITOR
if (!Application.isPlaying)
{
string[] searchFolders = { EditorSearchFolder };
string[] guids = AssetDatabase.FindAssets("t:HeroSkinSO", searchFolders);
if (guids != null && guids.Length > 0)
{
List<HeroSkinSO> result = new List<HeroSkinSO>(guids.Length);
for (int i = 0; i < guids.Length; i++)
{
string assetPath = AssetDatabase.GUIDToAssetPath(guids[i]);
HeroSkinSO skin = AssetDatabase.LoadAssetAtPath<HeroSkinSO>(assetPath);
if (skin != null)
{
result.Add(skin);
}
}
return result.ToArray();
}
string[] fallbackGuids = AssetDatabase.FindAssets("t:HeroSkinSO");
List<HeroSkinSO> fallback = new List<HeroSkinSO>(fallbackGuids.Length);
for (int i = 0; i < fallbackGuids.Length; i++)
{
string assetPath = AssetDatabase.GUIDToAssetPath(fallbackGuids[i]);
HeroSkinSO skin = AssetDatabase.LoadAssetAtPath<HeroSkinSO>(assetPath);
if (skin != null)
{
fallback.Add(skin);
}
}
return fallback.ToArray();
}
#endif
return RuntimeResourcesCache.LoadAllHeroSkins() ?? Array.Empty<HeroSkinSO>();
}
}