修了不少东西

This commit is contained in:
FloatGaming
2026-07-16 23:04:59 +08:00
parent 29972d0705
commit 73fe474cc6
134 changed files with 7673 additions and 741 deletions
+68 -4
View File
@@ -9,6 +9,9 @@ using UnityEditor;
[CreateAssetMenu(fileName = "NewAllyHero", menuName = "SO_Data/AllyHero")]
public class AllyHero_SO : ScriptableObject
{
private const string EquippedEquipmentSaveCategory = "ally_equipped_equipment";
private const string EquippedEquipmentRecoverySlotPrefix = "ally_equipped_equipment_";
public static readonly string[] BehaviourAxisNames =
{
"题海战术",
@@ -154,6 +157,13 @@ public class AllyHero_SO : ScriptableObject
public equipmentSO equippedEquipment;
public string equippedEquipmentId;
// 【性能】装备存档已从磁盘水合过一次的标记。水合后内存即权威来源:
// SetEquippedEquipment / ApplyEquippedEquipmentPayload / ClearEquippedEquipment 都会同步更新内存与磁盘,
// 因此无需反复解密读盘。idols 界面每次切换角色时 RebuildBag 会对"每件装备 × 每个英雄"调用
// LoadEquippedEquipmentFromLocal 做占用检查,若每次都真正解密 SecureSaveVault 会造成严重卡顿。
// 该标记确保每个英雄整个会话只读盘一次,之后走内存,行为完全不变。
[System.NonSerialized] private bool equippedEquipmentHydrated;
public SkillDefinition GetPrimarySkill()
{
if (availableSkills == null || primarySkillIndex < 0 || primarySkillIndex >= availableSkills.Length) return null;
@@ -506,12 +516,14 @@ public class AllyHero_SO : ScriptableObject
{
List<AllyLevelInfo> sorted = BuildSortedLevelStats();
int unlockedIndex = ResolveUnlockedLevelIndex(sorted);
if (unlockedIndex < 0 || unlockedIndex >= sorted.Count)
int expQualifiedIndex = ResolveExpQualifiedLevelIndex(sorted);
if (unlockedIndex < 0 || expQualifiedIndex < 0 || sorted == null || sorted.Count == 0)
{
return null;
}
return sorted[unlockedIndex];
int effectiveIndex = Mathf.Clamp(Mathf.Min(expQualifiedIndex, unlockedIndex), 0, sorted.Count - 1);
return sorted[effectiveIndex];
}
private List<AllyLevelInfo> BuildSortedLevelStats()
@@ -702,6 +714,16 @@ public class AllyHero_SO : ScriptableObject
return "ally_equippedEquipment_" + ally_heroID;
}
private string GetEquippedEquipmentSaveKey()
{
return ally_heroID.ToString();
}
private string GetEquippedEquipmentRecoverySlotKey()
{
return EquippedEquipmentRecoverySlotPrefix + ally_heroID;
}
private string GetSelectedSkinPrefsKey()
{
return "ally_selectedSkin_" + ally_heroID;
@@ -731,13 +753,39 @@ public class AllyHero_SO : ScriptableObject
equippedEquipmentId = equippedEquipment != null ? equippedEquipment.name : string.Empty;
var payload = new EquippedEquipmentPayload { equippedEquipmentId = equippedEquipmentId ?? string.Empty };
string json = JsonUtility.ToJson(payload);
SecureSaveVault.SaveJson(EquippedEquipmentSaveCategory, GetEquippedEquipmentSaveKey(), payload);
LocalRecoveryMirror.SaveJson(GetEquippedEquipmentRecoverySlotKey(), payload);
PlayerPrefs.SetString(GetEquippedEquipmentPrefsKey(), json);
PlayerPrefs.Save();
}
public void LoadEquippedEquipmentFromLocal()
public void LoadEquippedEquipmentFromLocal(bool forceReload = false)
{
// 已水合且非强制刷新时直接返回,避免重复解密读盘(见 equippedEquipmentHydrated 说明)。
if (equippedEquipmentHydrated && !forceReload)
{
return;
}
// 无论后续走哪条分支,本次调用都视为已完成水合:
// 命中存档→内存已填充;无存档→内存保持当前值,也不必反复重试读盘。
equippedEquipmentHydrated = true;
string key = GetEquippedEquipmentPrefsKey();
EquippedEquipmentPayload payload;
if (SecureSaveVault.TryLoadJson(EquippedEquipmentSaveCategory, GetEquippedEquipmentSaveKey(), out payload) && payload != null)
{
ApplyEquippedEquipmentPayload(payload);
return;
}
if (LocalRecoveryMirror.TryLoadJson(GetEquippedEquipmentRecoverySlotKey(), out payload) && payload != null)
{
ApplyEquippedEquipmentPayload(payload);
SecureSaveVault.SaveJson(EquippedEquipmentSaveCategory, GetEquippedEquipmentSaveKey(), payload);
return;
}
if (!PlayerPrefs.HasKey(key))
{
return;
@@ -749,7 +797,19 @@ public class AllyHero_SO : ScriptableObject
return;
}
EquippedEquipmentPayload payload = JsonUtility.FromJson<EquippedEquipmentPayload>(json);
payload = JsonUtility.FromJson<EquippedEquipmentPayload>(json);
if (payload == null)
{
return;
}
ApplyEquippedEquipmentPayload(payload);
SecureSaveVault.SaveJson(EquippedEquipmentSaveCategory, GetEquippedEquipmentSaveKey(), payload);
LocalRecoveryMirror.SaveJson(GetEquippedEquipmentRecoverySlotKey(), payload);
}
private void ApplyEquippedEquipmentPayload(EquippedEquipmentPayload payload)
{
if (payload == null)
{
return;
@@ -763,6 +823,7 @@ public class AllyHero_SO : ScriptableObject
{
equippedEquipment = equipment;
equippedEquipmentId = equipment != null ? equipment.name : string.Empty;
equippedEquipmentHydrated = true;
#if UNITY_EDITOR
if (!Application.isPlaying)
@@ -801,6 +862,9 @@ public class AllyHero_SO : ScriptableObject
{
equippedEquipment = null;
equippedEquipmentId = string.Empty;
equippedEquipmentHydrated = true;
SecureSaveVault.Delete(EquippedEquipmentSaveCategory, GetEquippedEquipmentSaveKey());
LocalRecoveryMirror.DeleteSlot(GetEquippedEquipmentRecoverySlotKey());
PlayerPrefs.DeleteKey(GetEquippedEquipmentPrefsKey());
PlayerPrefs.Save();
#if UNITY_EDITOR