343 lines
10 KiB
C#
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>();
|
|
}
|
|
}
|