using UnityEngine; public static class GameSaveManager { private const string SaveKey = "UniRun.SaveData.v1"; private const string LegacyTotalMileageKey = "UniRun.TotalMileage"; public static GameSaveData Load() { if(PlayerPrefs.HasKey(SaveKey)) { string json = PlayerPrefs.GetString(SaveKey); GameSaveData loadedData = JsonUtility.FromJson(json); if(loadedData != null) { Normalize(loadedData); return loadedData; } } GameSaveData saveData = GameSaveData.CreateDefault(); saveData.totalMileage = PlayerPrefs.GetInt(LegacyTotalMileageKey, 0); Normalize(saveData); Save(saveData); return saveData; } public static void Save(GameSaveData saveData) { Normalize(saveData); string json = JsonUtility.ToJson(saveData); PlayerPrefs.SetString(SaveKey, json); PlayerPrefs.SetInt(LegacyTotalMileageKey, saveData.totalMileage); PlayerPrefs.Save(); } public static GameSaveData ResetSave() { PlayerPrefs.DeleteKey(SaveKey); GameSaveData saveData = GameSaveData.CreateDefault(); Save(saveData); return saveData; } public static void AddMileage(GameSaveData saveData, int amount) { if(saveData == null) { return; } saveData.totalMileage = Mathf.Max(0, saveData.totalMileage + amount); Save(saveData); } public static void UnlockMap(GameSaveData saveData, MapId mapId) { if(saveData == null) { return; } int mapIndex = MapDatabase.GetIndex(mapId); saveData.unlockedMapIndex = Mathf.Max(saveData.unlockedMapIndex, mapIndex); Save(saveData); } private static void Normalize(GameSaveData saveData) { saveData.currentMapIndex = Mathf.Clamp(saveData.currentMapIndex, 0, MapDatabase.LastMapIndex); saveData.unlockedMapIndex = Mathf.Clamp(saveData.unlockedMapIndex, 0, MapDatabase.LastMapIndex); saveData.currentMapIndex = Mathf.Min(saveData.currentMapIndex, saveData.unlockedMapIndex); saveData.totalMileage = Mathf.Max(0, saveData.totalMileage); saveData.bagSlots = Mathf.Clamp(saveData.bagSlots, 1, 3); saveData.lunchboxStock = Mathf.Max(0, saveData.lunchboxStock); saveData.mileageCardStock = Mathf.Max(0, saveData.mileageCardStock); saveData.supplementPurchases = Mathf.Clamp(saveData.supplementPurchases, 0, 4); saveData.dutyFreeLimitStageIndex = saveData.dutyFreeLimitStageIndex < 0 ? -1 : Mathf.Clamp(saveData.dutyFreeLimitStageIndex, 0, MapDatabase.LastMapIndex); NormalizeEquippedItems(saveData); NormalizeDutyFreeStockCapacity(saveData); NormalizeEquippedItems(saveData); saveData.bestScore = Mathf.Max(0, saveData.bestScore); } private static void NormalizeDutyFreeStockCapacity(GameSaveData saveData) { int bagSlots = Mathf.Clamp(saveData.bagSlots, 1, 3); int equippedLunchboxes = CountEquippedItem(saveData, DutyFreeItemType.Lunchbox, bagSlots); int equippedMileageCards = CountEquippedItem(saveData, DutyFreeItemType.MileageCard, bagSlots); saveData.lunchboxStock = Mathf.Max(equippedLunchboxes, Mathf.Min(saveData.lunchboxStock, bagSlots)); saveData.mileageCardStock = Mathf.Max(equippedMileageCards, Mathf.Min(saveData.mileageCardStock, bagSlots)); while(saveData.lunchboxStock + saveData.mileageCardStock > bagSlots) { if(saveData.mileageCardStock > equippedMileageCards) { saveData.mileageCardStock--; } else if(saveData.lunchboxStock > equippedLunchboxes) { saveData.lunchboxStock--; } else { break; } } } private static int CountEquippedItem(GameSaveData saveData, DutyFreeItemType itemType, int bagSlots) { int count = 0; for(int i = 0; i < bagSlots; i++) { if(GetEquippedSlot(saveData, i) == itemType) { count++; } } return count; } private static void NormalizeEquippedItems(GameSaveData saveData) { int bagSlots = Mathf.Clamp(saveData.bagSlots, 1, 3); if(bagSlots < 3) { saveData.equippedSlot3 = DutyFreeItemType.None; } if(bagSlots < 2) { saveData.equippedSlot2 = DutyFreeItemType.None; } saveData.equippedSlot1 = NormalizeItemType(saveData.equippedSlot1); saveData.equippedSlot2 = NormalizeItemType(saveData.equippedSlot2); saveData.equippedSlot3 = NormalizeItemType(saveData.equippedSlot3); int lunchboxCount = 0; int mileageCardCount = 0; ClampEquippedSlot(saveData, 0, ref lunchboxCount, ref mileageCardCount); ClampEquippedSlot(saveData, 1, ref lunchboxCount, ref mileageCardCount); ClampEquippedSlot(saveData, 2, ref lunchboxCount, ref mileageCardCount); } private static DutyFreeItemType NormalizeItemType(DutyFreeItemType itemType) { switch(itemType) { case DutyFreeItemType.Lunchbox: case DutyFreeItemType.MileageCard: return itemType; default: return DutyFreeItemType.None; } } private static void ClampEquippedSlot( GameSaveData saveData, int slotIndex, ref int lunchboxCount, ref int mileageCardCount) { DutyFreeItemType itemType = GetEquippedSlot(saveData, slotIndex); if(itemType == DutyFreeItemType.None) { return; } bool overStock = false; switch(itemType) { case DutyFreeItemType.Lunchbox: overStock = lunchboxCount >= saveData.lunchboxStock; lunchboxCount++; break; case DutyFreeItemType.MileageCard: overStock = mileageCardCount >= saveData.mileageCardStock; mileageCardCount++; break; } if(overStock) { SetEquippedSlot(saveData, slotIndex, DutyFreeItemType.None); } } private static DutyFreeItemType GetEquippedSlot(GameSaveData saveData, int slotIndex) { switch(slotIndex) { case 0: return saveData.equippedSlot1; case 1: return saveData.equippedSlot2; case 2: return saveData.equippedSlot3; default: return DutyFreeItemType.None; } } private static void SetEquippedSlot(GameSaveData saveData, int slotIndex, DutyFreeItemType itemType) { switch(slotIndex) { case 0: saveData.equippedSlot1 = itemType; break; case 1: saveData.equippedSlot2 = itemType; break; case 2: saveData.equippedSlot3 = itemType; break; } } }