Files
bansonic_beta_main/Assets/scripts/_runtimecache/PlayerProgressBackupService.cs
T

556 lines
15 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
[Serializable]
public class PlayerProgressBackupBundle
{
public int version = 1;
public long savedUtcTicks;
public PlayerEconomyPayload economy;
public int playerExperience;
public float bestOverallRks;
public PlayerSkillSaveData playerSkill;
public AllyHeroDeployLedgerPayload allyHeroDeploy;
public ExpBottleLedgerPayload expBottle;
public DushMaterialLedgerPayload dushMaterial;
public EquipmentConsumableLedgerPayload equipmentConsumable;
public StoreOwnershipPayload storeOwnership;
}
public static class PlayerProgressBackupService
{
private const string BackupFileName = "player_progress.bbackup";
private static PlayerProgressBackupBundle s_cachedBundle;
private static bool s_cacheLoaded;
private static bool s_isWriting;
public static bool TryRestoreEconomy(out PlayerEconomyPayload payload)
{
payload = null;
PlayerProgressBackupBundle bundle;
if (!TryLoadBundle(out bundle) || bundle == null || bundle.economy == null)
{
return false;
}
payload = CloneEconomy(bundle.economy);
return payload != null;
}
public static void SaveEconomy(PlayerEconomyPayload payload)
{
if (payload == null)
{
return;
}
UpdateBundle(bundle => bundle.economy = CloneEconomy(payload));
}
public static bool TryRestorePlayerExperience(out int experience)
{
experience = 0;
PlayerProgressBackupBundle bundle;
if (!TryLoadBundle(out bundle) || bundle == null)
{
return false;
}
if (bundle.playerExperience <= 0)
{
return false;
}
experience = Mathf.Max(0, bundle.playerExperience);
return true;
}
public static void SavePlayerExperience(int experience)
{
UpdateBundle(bundle => bundle.playerExperience = Mathf.Max(0, experience));
}
public static bool TryRestoreRks(out float rks)
{
rks = 0f;
PlayerProgressBackupBundle bundle;
if (!TryLoadBundle(out bundle) || bundle == null || bundle.bestOverallRks <= 0f)
{
return false;
}
rks = Mathf.Max(0f, bundle.bestOverallRks);
return true;
}
public static void SaveRks(float rks)
{
UpdateBundle(bundle => bundle.bestOverallRks = Mathf.Max(0f, rks));
}
public static bool TryRestorePlayerSkill(out PlayerSkillSaveData saveData)
{
saveData = null;
PlayerProgressBackupBundle bundle;
if (!TryLoadBundle(out bundle) || bundle == null || bundle.playerSkill == null)
{
return false;
}
saveData = ClonePlayerSkill(bundle.playerSkill);
return saveData != null;
}
public static void SavePlayerSkill(PlayerSkillSaveData saveData)
{
if (saveData == null)
{
return;
}
UpdateBundle(bundle => bundle.playerSkill = ClonePlayerSkill(saveData));
}
public static bool TryRestoreAllyHeroDeploy(out AllyHeroDeployLedgerPayload payload)
{
payload = null;
PlayerProgressBackupBundle bundle;
if (!TryLoadBundle(out bundle) || bundle == null || bundle.allyHeroDeploy == null)
{
return false;
}
payload = CloneAllyHeroDeploy(bundle.allyHeroDeploy);
return payload != null;
}
public static void SaveAllyHeroDeploy(AllyHeroDeployLedgerPayload payload)
{
if (payload == null)
{
return;
}
UpdateBundle(bundle => bundle.allyHeroDeploy = CloneAllyHeroDeploy(payload));
}
public static bool TryRestoreExpBottle(out ExpBottleLedgerPayload payload)
{
payload = null;
PlayerProgressBackupBundle bundle;
if (!TryLoadBundle(out bundle) || bundle == null || bundle.expBottle == null)
{
return false;
}
payload = CloneExpBottle(bundle.expBottle);
return payload != null;
}
public static void SaveExpBottle(ExpBottleLedgerPayload payload)
{
if (payload == null)
{
return;
}
UpdateBundle(bundle => bundle.expBottle = CloneExpBottle(payload));
}
public static bool TryRestoreDushMaterial(out DushMaterialLedgerPayload payload)
{
payload = null;
PlayerProgressBackupBundle bundle;
if (!TryLoadBundle(out bundle) || bundle == null || bundle.dushMaterial == null)
{
return false;
}
payload = CloneDushMaterial(bundle.dushMaterial);
return payload != null;
}
public static void SaveDushMaterial(DushMaterialLedgerPayload payload)
{
if (payload == null)
{
return;
}
UpdateBundle(bundle => bundle.dushMaterial = CloneDushMaterial(payload));
}
public static bool TryRestoreEquipmentConsumable(out EquipmentConsumableLedgerPayload payload)
{
payload = null;
PlayerProgressBackupBundle bundle;
if (!TryLoadBundle(out bundle) || bundle == null || bundle.equipmentConsumable == null)
{
return false;
}
payload = CloneEquipmentConsumable(bundle.equipmentConsumable);
return payload != null;
}
public static void SaveEquipmentConsumable(EquipmentConsumableLedgerPayload payload)
{
if (payload == null)
{
return;
}
UpdateBundle(bundle => bundle.equipmentConsumable = CloneEquipmentConsumable(payload));
}
public static bool TryRestoreStoreOwnership(out StoreOwnershipPayload payload)
{
payload = null;
PlayerProgressBackupBundle bundle;
if (!TryLoadBundle(out bundle) || bundle == null || bundle.storeOwnership == null)
{
return false;
}
payload = CloneStoreOwnership(bundle.storeOwnership);
return payload != null;
}
public static void SaveStoreOwnership(StoreOwnershipPayload payload)
{
if (payload == null)
{
return;
}
UpdateBundle(bundle => bundle.storeOwnership = CloneStoreOwnership(payload));
}
private static void UpdateBundle(Action<PlayerProgressBackupBundle> mutator)
{
if (mutator == null || s_isWriting)
{
return;
}
PlayerProgressBackupBundle bundle;
if (!TryLoadBundle(out bundle) || bundle == null)
{
bundle = CreateDefaultBundle();
}
mutator(bundle);
bundle.savedUtcTicks = DateTime.UtcNow.Ticks;
SaveBundle(bundle);
}
private static bool TryLoadBundle(out PlayerProgressBackupBundle bundle)
{
if (s_cacheLoaded)
{
bundle = s_cachedBundle;
return bundle != null;
}
s_cacheLoaded = true;
s_cachedBundle = null;
IReadOnlyList<string> candidates = SaveIdentityUtility.GetPersistentRootVariants();
for (int i = 0; i < candidates.Count; i++)
{
string root = candidates[i];
if (string.IsNullOrWhiteSpace(root))
{
continue;
}
string path = Path.Combine(root, BackupFileName);
if (!File.Exists(path))
{
continue;
}
try
{
string json = File.ReadAllText(path, Encoding.UTF8);
if (string.IsNullOrWhiteSpace(json))
{
continue;
}
PlayerProgressBackupBundle loaded = JsonUtility.FromJson<PlayerProgressBackupBundle>(json);
if (loaded == null)
{
continue;
}
s_cachedBundle = loaded;
break;
}
catch (Exception ex)
{
Debug.LogWarning("[PlayerProgressBackup] Failed to read backup '" + path + "': " + ex.Message);
}
}
bundle = s_cachedBundle;
return bundle != null;
}
private static void SaveBundle(PlayerProgressBackupBundle bundle)
{
if (bundle == null)
{
return;
}
string root = SaveIdentityUtility.GetCanonicalPersistentRoot();
string path = Path.Combine(root, BackupFileName);
try
{
s_isWriting = true;
Directory.CreateDirectory(root);
string json = JsonUtility.ToJson(bundle, false);
File.WriteAllText(path, json, Encoding.UTF8);
s_cachedBundle = bundle;
s_cacheLoaded = true;
}
catch (Exception ex)
{
Debug.LogWarning("[PlayerProgressBackup] Failed to save backup '" + path + "': " + ex.Message);
}
finally
{
s_isWriting = false;
}
}
private static PlayerProgressBackupBundle CreateDefaultBundle()
{
return new PlayerProgressBackupBundle
{
version = 1,
savedUtcTicks = DateTime.UtcNow.Ticks
};
}
private static PlayerEconomyPayload CloneEconomy(PlayerEconomyPayload source)
{
if (source == null)
{
return null;
}
return new PlayerEconomyPayload
{
version = source.version,
lastUpdatedUtcTicks = source.lastUpdatedUtcTicks,
coins = source.coins,
material = source.material
};
}
private static PlayerSkillSaveData ClonePlayerSkill(PlayerSkillSaveData source)
{
if (source == null)
{
return null;
}
return new PlayerSkillSaveData
{
selectedSkillIndex = source.selectedSkillIndex,
postMatchRewardCounter = source.postMatchRewardCounter,
skillSwitchCooldownRemainingMatches = source.skillSwitchCooldownRemainingMatches
};
}
private static AllyHeroDeployLedgerPayload CloneAllyHeroDeploy(AllyHeroDeployLedgerPayload source)
{
if (source == null)
{
return null;
}
var clone = new AllyHeroDeployLedgerPayload
{
version = source.version,
lastUpdatedUtcTicks = source.lastUpdatedUtcTicks,
entries = new List<AllyHeroDeployEntry>()
};
if (source.entries != null)
{
for (int i = 0; i < source.entries.Count; i++)
{
AllyHeroDeployEntry entry = source.entries[i];
if (entry == null)
{
continue;
}
clone.entries.Add(new AllyHeroDeployEntry
{
heroId = entry.heroId,
currentExp = entry.currentExp,
unlockedTierIndex = entry.unlockedTierIndex,
levelLock = entry.levelLock,
autoBreakthroughEnabled = entry.autoBreakthroughEnabled,
deployCount = entry.deployCount,
finishCount = entry.finishCount,
mvpCount = entry.mvpCount,
joinDateUtcTicks = entry.joinDateUtcTicks
});
}
}
return clone;
}
private static ExpBottleLedgerPayload CloneExpBottle(ExpBottleLedgerPayload source)
{
if (source == null)
{
return null;
}
var clone = new ExpBottleLedgerPayload
{
version = source.version,
lastUpdatedUtcTicks = source.lastUpdatedUtcTicks,
entries = new List<ExpBottleEntry>()
};
if (source.entries != null)
{
for (int i = 0; i < source.entries.Count; i++)
{
ExpBottleEntry entry = source.entries[i];
if (entry == null)
{
continue;
}
clone.entries.Add(new ExpBottleEntry
{
key = entry.key,
count = entry.count
});
}
}
return clone;
}
private static DushMaterialLedgerPayload CloneDushMaterial(DushMaterialLedgerPayload source)
{
if (source == null)
{
return null;
}
var clone = new DushMaterialLedgerPayload
{
version = source.version,
lastUpdatedUtcTicks = source.lastUpdatedUtcTicks,
entries = new List<DushMaterialEntry>()
};
if (source.entries != null)
{
for (int i = 0; i < source.entries.Count; i++)
{
DushMaterialEntry entry = source.entries[i];
if (entry == null)
{
continue;
}
clone.entries.Add(new DushMaterialEntry
{
key = entry.key,
count = entry.count
});
}
}
return clone;
}
private static EquipmentConsumableLedgerPayload CloneEquipmentConsumable(EquipmentConsumableLedgerPayload source)
{
if (source == null)
{
return null;
}
var clone = new EquipmentConsumableLedgerPayload
{
version = source.version,
lastUpdatedUtcTicks = source.lastUpdatedUtcTicks,
entries = new List<EquipmentConsumableEntry>()
};
if (source.entries != null)
{
for (int i = 0; i < source.entries.Count; i++)
{
EquipmentConsumableEntry entry = source.entries[i];
if (entry == null)
{
continue;
}
clone.entries.Add(new EquipmentConsumableEntry
{
key = entry.key,
count = entry.count
});
}
}
return clone;
}
private static StoreOwnershipPayload CloneStoreOwnership(StoreOwnershipPayload source)
{
if (source == null)
{
return null;
}
var clone = new StoreOwnershipPayload
{
version = source.version,
lastUpdatedUtcTicks = source.lastUpdatedUtcTicks,
entries = new List<StoreOwnershipEntry>()
};
if (source.entries != null)
{
for (int i = 0; i < source.entries.Count; i++)
{
StoreOwnershipEntry entry = source.entries[i];
if (entry == null)
{
continue;
}
clone.entries.Add(new StoreOwnershipEntry
{
storeItemId = entry.storeItemId,
owned = entry.owned,
unlockedStorySonIds = entry.unlockedStorySonIds != null
? new List<int>(entry.unlockedStorySonIds)
: new List<int>()
});
}
}
return clone;
}
}