207 lines
7.0 KiB
C#
207 lines
7.0 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
#endif
|
|
|
|
public static class EquipmentSkillGroupLibrary
|
|
{
|
|
private static readonly string[] SpecialResourcesPaths =
|
|
{
|
|
"so/skill_equipSkills/mmrEffectSkills",
|
|
"so/skill_equipSkills/\u8bb0\u5fc6\u7279\u6548\u6280\u80fd"
|
|
};
|
|
|
|
private static readonly string[] IllusionResourcesPaths =
|
|
{
|
|
"so/skill_equipSkills/illusionSkills",
|
|
"so/skill_equipSkills/\u5e7b\u5316\u6280\u80fd"
|
|
};
|
|
|
|
#if UNITY_EDITOR
|
|
private static readonly string[] SpecialAssetFolders =
|
|
{
|
|
"Assets/Resources/so/skill_equipSkills/mmrEffectSkills",
|
|
"Assets/Resources/so/skill_equipSkills/\u8bb0\u5fc6\u7279\u6548\u6280\u80fd"
|
|
};
|
|
|
|
private static readonly string[] IllusionAssetFolders =
|
|
{
|
|
"Assets/Resources/so/skill_equipSkills/illusionSkills",
|
|
"Assets/Resources/so/skill_equipSkills/\u5e7b\u5316\u6280\u80fd"
|
|
};
|
|
#endif
|
|
|
|
public static SkillGroup ResolveSpecialSkillGroup(int skillGroupId)
|
|
{
|
|
return ResolveSkillGroup(skillGroupId, EquipmentSkillGroupSO.EquipmentSkillCategory.Special);
|
|
}
|
|
|
|
public static SkillGroup ResolveIllusionSkillGroup(int skillGroupId)
|
|
{
|
|
return ResolveSkillGroup(skillGroupId, EquipmentSkillGroupSO.EquipmentSkillCategory.Illusion);
|
|
}
|
|
|
|
public static SkillGroup ResolveSkillGroup(int skillGroupId)
|
|
{
|
|
SkillGroup group = ResolveSpecialSkillGroup(skillGroupId);
|
|
if (group != null)
|
|
{
|
|
return group;
|
|
}
|
|
|
|
return ResolveIllusionSkillGroup(skillGroupId);
|
|
}
|
|
|
|
public static SkillGroup ResolveSkillGroup(int skillGroupId, EquipmentSkillGroupSO.EquipmentSkillCategory category)
|
|
{
|
|
if (skillGroupId <= 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
EquipmentSkillGroupSO asset = FindAsset(skillGroupId, category);
|
|
return asset != null ? asset.skillGroup : null;
|
|
}
|
|
|
|
// --- Runtime cache -------------------------------------------------------
|
|
// Equipment skill-group assets are static config loaded from Resources and never
|
|
// mutated at runtime, so both the per-category asset list and the id->asset resolution
|
|
// are memoized during play mode. This turns a per-note/per-trigger Resources.LoadAll +
|
|
// collection-allocation storm into O(1) dictionary lookups. The editor (!isPlaying)
|
|
// path stays uncached so asset edits are always reflected; the cache is cleared on
|
|
// play-mode start via RuntimeInitializeOnLoadMethod so a fresh session never sees stale
|
|
// entries from a prior play session (domain-reload-disabled projects).
|
|
private static readonly Dictionary<EquipmentSkillGroupSO.EquipmentSkillCategory, List<EquipmentSkillGroupSO>> s_assetsByCategory =
|
|
new Dictionary<EquipmentSkillGroupSO.EquipmentSkillCategory, List<EquipmentSkillGroupSO>>();
|
|
// Keyed by (category, skillGroupId); caches both hits and misses (null value = confirmed miss).
|
|
private static readonly Dictionary<long, EquipmentSkillGroupSO> s_findAssetCache = new Dictionary<long, EquipmentSkillGroupSO>();
|
|
|
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
|
private static void ResetRuntimeCache()
|
|
{
|
|
s_assetsByCategory.Clear();
|
|
s_findAssetCache.Clear();
|
|
}
|
|
|
|
private static long MakeFindKey(int skillGroupId, EquipmentSkillGroupSO.EquipmentSkillCategory category)
|
|
{
|
|
return ((long)category << 32) | (uint)skillGroupId;
|
|
}
|
|
|
|
public static EquipmentSkillGroupSO FindAsset(int skillGroupId, EquipmentSkillGroupSO.EquipmentSkillCategory category)
|
|
{
|
|
if (skillGroupId <= 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
bool useCache = Application.isPlaying;
|
|
long findKey = 0;
|
|
if (useCache)
|
|
{
|
|
findKey = MakeFindKey(skillGroupId, category);
|
|
if (s_findAssetCache.TryGetValue(findKey, out EquipmentSkillGroupSO cached))
|
|
{
|
|
return cached;
|
|
}
|
|
}
|
|
|
|
var assets = LoadAssets(category);
|
|
EquipmentSkillGroupSO resolved = null;
|
|
for (int i = 0; i < assets.Count; i++)
|
|
{
|
|
EquipmentSkillGroupSO asset = assets[i];
|
|
if (asset == null || asset.skillGroup == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (asset.skillGroup.skillGroupID == skillGroupId)
|
|
{
|
|
resolved = asset;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (useCache)
|
|
{
|
|
// Cache hits AND misses (null) so repeated unmatched ids don't re-scan.
|
|
s_findAssetCache[findKey] = resolved;
|
|
}
|
|
|
|
return resolved;
|
|
}
|
|
|
|
public static List<EquipmentSkillGroupSO> LoadAssets(EquipmentSkillGroupSO.EquipmentSkillCategory category)
|
|
{
|
|
// Play mode: build the per-category list once (from Resources) and reuse it.
|
|
if (Application.isPlaying && s_assetsByCategory.TryGetValue(category, out var cachedList))
|
|
{
|
|
return cachedList;
|
|
}
|
|
|
|
var results = new List<EquipmentSkillGroupSO>();
|
|
|
|
#if UNITY_EDITOR
|
|
if (!Application.isPlaying)
|
|
{
|
|
string[] folders = category == EquipmentSkillGroupSO.EquipmentSkillCategory.Special ? SpecialAssetFolders : IllusionAssetFolders;
|
|
var dedupe = new HashSet<string>();
|
|
for (int folderIndex = 0; folderIndex < folders.Length; folderIndex++)
|
|
{
|
|
if (!AssetDatabase.IsValidFolder(folders[folderIndex]))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
string[] guids = AssetDatabase.FindAssets("t:EquipmentSkillGroupSO", new[] { folders[folderIndex] });
|
|
for (int i = 0; i < guids.Length; i++)
|
|
{
|
|
string path = AssetDatabase.GUIDToAssetPath(guids[i]);
|
|
if (!dedupe.Add(path))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
EquipmentSkillGroupSO asset = AssetDatabase.LoadAssetAtPath<EquipmentSkillGroupSO>(path);
|
|
if (asset != null)
|
|
{
|
|
results.Add(asset);
|
|
}
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|
|
#endif
|
|
|
|
string[] resourcePaths = category == EquipmentSkillGroupSO.EquipmentSkillCategory.Special ? SpecialResourcesPaths : IllusionResourcesPaths;
|
|
var seen = new HashSet<EquipmentSkillGroupSO>();
|
|
for (int i = 0; i < resourcePaths.Length; i++)
|
|
{
|
|
EquipmentSkillGroupSO[] loaded = Resources.LoadAll<EquipmentSkillGroupSO>(resourcePaths[i]);
|
|
if (loaded == null || loaded.Length == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
for (int j = 0; j < loaded.Length; j++)
|
|
{
|
|
if (loaded[j] != null && seen.Add(loaded[j]))
|
|
{
|
|
results.Add(loaded[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Application.isPlaying)
|
|
{
|
|
s_assetsByCategory[category] = results;
|
|
}
|
|
|
|
return results;
|
|
}
|
|
}
|