Hey again,
Caching stores all of the keys in memory so that it can perform operations in memory, rather than having to perform expensive File IO everytime you save or load to/from a file. The guide I linked shows how you would use caching.
ok Ill read it throughly thanks
![Smile :)](./images/smilies/icon_e_smile.gif)
).
Please could you post the code you're using to save and load
Code: Select all
using System;
using System.Collections.Generic;
using UnityEngine;
using RL.StartMenu;
namespace RL.Core
{
public class SaveManager : MonoBehaviour
{
#region --- Singleton ---
public static SaveManager Instance;
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(this.gameObject);
return;
}
Instance = this;
AfterSingletonAwake();
}
#endregion
public readonly int SaveSlotCount = 3;
public string Path { get; private set; }
public event Action OnSetupSaveSlots;
public event Action OnSave;
public event Action OnLoad;
public event Action OnDelete;
private const string DEFAULT_PATH_STRING = "_defaultPath";
private void AfterSingletonAwake()
{
//InvokeRepeating(nameof(AutoSave), 1f, 60f);
//DeleteFile(DEFAULT_PATH_STRING);
}
private void Start()
{
if (StartMenuManager.Instance != null)
StartMenuManager.Instance.OnLoadIntoGameEvent += OnLoadIntoGame;
SceneLoader.i.OnTransitionSceneEvent += Save;
Invoke(nameof(SetSaveSlotData), 0.1f);
Invoke(nameof(Load), 0.2f);
}
public void OnLoadIntoGame()
{
foreach (var slot in SaveSlotDatas)
{
slot.RemoveOnDeleteEvent();
}
}
public void AutoSave()
{
if (SceneLoader.i.IsStartMenuScene) return;
Save();
}
public void Setup(string path)
{
this.Path = path;
ES3Settings.defaultSettings.path = Path;
}
public List<SaveSlotData> SaveSlotDatas { get; private set; } = new();
public void SetSaveSlotData()
{
for (int i = 0; i < SaveSlotCount; i++)
{
SaveSlotData s = new(i);
if (s.HasSaveSlot())
{
s.Load();
}
SaveSlotDatas.Add(s);
}
OnSetupSaveSlots?.Invoke();
}
public SaveSlotData GetSaveSlot(int j) => SaveSlotDatas[j];
public SaveSlotData CurrentSaveSlot { get; private set; }
public void SetCurrentSaveSlot(SaveSlotData data)
{
if (data == null) return;
CurrentSaveSlot = data;
Setup(CurrentSaveSlot.GetSaveSlotName());
}
public void Save()
{
//Debug.Log("Save");
OnSave?.Invoke();
CurrentSaveSlot?.SetSaveSlot();
foreach (var saveData in saveDataOnDefaultPathDictionary)
{
Debug.Log("Default Save: " + saveData.Key);
SaveData(saveData.Key, saveData.Value, DEFAULT_PATH_STRING);
}
saveDataOnDefaultPathDictionary.Clear();
foreach (var saveData in saveDataOnSaveSlotDictionary)
{
Debug.Log("Save Slot Save: " + saveData.Key);
if (saveData.Value == null)
DeleteData(saveData.Key);
else
SaveData(saveData.Key, saveData.Value, ES3Settings.defaultSettings.path);
}
saveDataOnSaveSlotDictionary.Clear();
foreach (var deleteData in deleteDataOnSaveSlotDictionary)
{
Debug.Log("Delete Save: " + deleteData.Key);
DeleteData(deleteData.Key);
}
deleteDataOnSaveSlotDictionary.Clear();
}
public void Load()
{
OnLoad?.Invoke();
CurrentSaveSlot?.Load();
}
private Dictionary<object, object> saveDataOnDefaultPathDictionary = new();
public void SaveDataOnDefault(object saveKey, object saveValue)
{
if (saveDataOnDefaultPathDictionary != null && saveDataOnDefaultPathDictionary.Count > 0)
{
if (saveDataOnDefaultPathDictionary.ContainsKey(saveKey))
{
saveDataOnDefaultPathDictionary[saveKey] = saveValue;
return;
}
}
saveDataOnDefaultPathDictionary.Add(saveKey, saveValue);
}
public object LoadDataOnDefault(object loadKey, object defaultValue)
{
return ES3.Load(loadKey.ToString(), DEFAULT_PATH_STRING, defaultValue);
}
public void DeleteKeyOnDefault(string key)
{
ES3.DeleteKey(key, DEFAULT_PATH_STRING);
}
private Dictionary<object, object> saveDataOnSaveSlotDictionary = new();
public void AddToSaveData(object saveKey, object saveValue)
{
if (saveDataOnSaveSlotDictionary != null && saveDataOnSaveSlotDictionary.Count > 0)
{
if (saveDataOnSaveSlotDictionary.ContainsKey(saveKey))
{
saveDataOnSaveSlotDictionary[saveKey] = saveValue;
return;
}
}
saveDataOnSaveSlotDictionary.Add(saveKey, saveValue);
}
public void SaveData(object saveKey, object saveValue, string path)
{
if (saveValue == null)
{
Debug.LogError("Save Value is null");
return;
}
ES3.Save(saveKey.ToString(), saveValue, path);
}
public object LoadData(object loadKey)
{
return LoadData(loadKey, null);
}
private Dictionary<object, object> deleteDataOnSaveSlotDictionary = new();
public void AddToDeleteData(object saveKey)
{
AddToSaveData(saveKey, null);
return;
if (deleteDataOnSaveSlotDictionary != null && deleteDataOnSaveSlotDictionary.Count > 0)
{
if (deleteDataOnSaveSlotDictionary.ContainsKey(saveKey)) return;
}
deleteDataOnSaveSlotDictionary.Add(saveKey, null);
}
public object LoadData(object loadKey, object defaultValue)
{
if (ES3.KeyExists(loadKey.ToString()))
return ES3.Load(loadKey.ToString(), ES3Settings.defaultSettings.path, defaultValue);
return defaultValue;
}
public void DeleteData(object deleteKey)
{
ES3.DeleteKey(deleteKey.ToString(), ES3Settings.defaultSettings.path);
}
public void DeleteKey(string key)
{
ES3.DeleteKey(key);
}
public void DeleteFile()
{
DeleteFile(ES3Settings.defaultSettings.path);
}
public void DeleteFile(string path)
{
ES3.DeleteFile(path);
}
public string GetLastDatePlayed() => System.DateTime.Now.ToString("MM/dd/yyyy");
public string GetLastTimePlayed() => System.DateTime.Now.ToString("hh:mm:ss");
public void Delete() => OnDelete?.Invoke();
private void OnApplicationQuit()
{
if (!Application.isEditor)
Save();
}
}
public class SaveSlotData
{
public int index;
public bool hasSaveSlot;
public float playTime;
public string lastDatePlayed;
public string lastTimePlayed;
private string HasSaveSlotIndex() => GetSaveSlotName() + "_hasSaveSlot";
private string PlayTimeIndex() => GetSaveSlotName() + "_playTime";
private string LastDatePlayedIndex() => GetSaveSlotName() + "_lastDatePlayed";
private string LastTimePlayedIndex() => GetSaveSlotName() + "_lastTimePlayed";
public SaveSlotData(int i)
{
SaveManager.Instance.OnDelete += Delete;
index = i;
ResetData(false);
}
public string GetSaveSlotName() => "SaveSlot" + index;
public bool HasSaveSlot() => (bool)SaveManager.Instance.LoadDataOnDefault(HasSaveSlotIndex(), false);
public string PlayedTimeString()
{
System.Text.StringBuilder sb = new();
float playedTimeHours = Mathf.Floor(playTime / 3600);
float playTimeMinutes = Mathf.Floor((playTime / 60) % 60);
float playTimeSeconds = Mathf.Floor(playTime % 60);
bool hasPlayTimeHours = playedTimeHours >= 1f;
if (hasPlayTimeHours) sb.Append($"{playedTimeHours}h ");
if (playTimeMinutes >= 1f) sb.Append($"{playTimeMinutes} min");
if (!hasPlayTimeHours && playTimeSeconds >= 1f) sb.Append($" {playTimeSeconds} sec");
return sb.ToString();
}
public void ResetData(bool save)
{
hasSaveSlot = false;
playTime = 0f;
lastDatePlayed = "";
lastTimePlayed = "";
if (save) Save();
}
public void Load()
{
hasSaveSlot = HasSaveSlot();
playTime = (float)SaveManager.Instance.LoadDataOnDefault(PlayTimeIndex(), 0f);
lastDatePlayed = (string)SaveManager.Instance.LoadDataOnDefault(LastDatePlayedIndex(), "");
lastTimePlayed = (string)SaveManager.Instance.LoadDataOnDefault(LastTimePlayedIndex(), "");
}
public void SetSaveSlot()
{
hasSaveSlot = true;
playTime += GameManager.Instance.CurrentPlayTime;
lastDatePlayed = SaveManager.Instance.GetLastDatePlayed();
lastTimePlayed = SaveManager.Instance.GetLastTimePlayed();
Save();
}
public void Save()
{
SaveManager.Instance.SaveDataOnDefault(HasSaveSlotIndex(), hasSaveSlot);
SaveManager.Instance.SaveDataOnDefault(PlayTimeIndex(), playTime);
SaveManager.Instance.SaveDataOnDefault(LastDatePlayedIndex(), lastDatePlayed);
SaveManager.Instance.SaveDataOnDefault(LastTimePlayedIndex(), lastTimePlayed);
GameManager.Instance.ResetCurrentPlayTime();
}
public void Delete()
{
SaveManager.Instance.LoadDataOnDefault(GetSaveSlotName());
ResetData(true);
}
public void RemoveOnDeleteEvent() => SaveManager.Instance.OnDelete -= Delete;
}
}
and the ScriptableObjects you are saving,
Code: Select all
using System;
using System.Collections.Generic;
using UnityEngine;
using Sirenix.OdinInspector;
using CodeStage.AntiCheat.ObscuredTypes;
using RL.Core;
using RL.Player;
namespace RL.Items
{
[CreateAssetMenu(fileName = "Equip Item", menuName = "Equipment/Equip Item")]
public class EquipItem : ScriptableObject
{
public string GetID() => $"{playerClassType}_{rarity}_{equipmentType}_{itemName}";
[Space]
[TitleGroup("General")]
[HorizontalGroup("General/Data", 100), PreviewField(100), PropertySpace(SpaceBefore = 0, SpaceAfter = 7), HideLabel]
public Sprite itemIcon;
[VerticalGroup("General/Data/Right"), LabelWidth(50), LabelText("Name")]
public string itemName;
[VerticalGroup("General/Data/Right"), LabelWidth(80), LabelText("Class")]
public PlayerClassType playerClassType;
[VerticalGroup("General/Data/Right"), LabelWidth(80), LabelText("Rarity")]
public ItemRarity rarity;
[VerticalGroup("General/Data/Right"), LabelWidth(80), LabelText("Equipment")]
public EquipmentType equipmentType;
[VerticalGroup("General/Data/Right"), LabelWidth(80), LabelText("Specific Stats")]
public bool hasSpecificStats;
public bool hasSpecificAffix;
public bool hasSpecificSet;
[VerticalGroup("General/Data/Right"), LabelWidth(80), LabelText("Max Stats")]
public bool hasMaxStats = false;
[ShowIf("hasSpecificStats", true), LabelText("Specific Stats")]
public List<ItemStatType> specificStatsList = new();
[ShowIf("hasSpecificAffix", true), LabelText("Specific Affix")]
public ItemAffix specificItemAffix;
[ShowIf("hasSpecificSet", true), LabelText("Specific Set")]
public ItemSetData specificItemSetData;
[LabelWidth(50), TextArea(), LabelText("Description")]
public string itemDescription;
public BaseItemSlot ItemSlot { get; private set; }
public PlayerStatsHolder PlayerStatsHolder { get; private set; }
public List<EquipmentItemStat> AllPossibleStatList { get; private set; } = new();
public List<EquipmentItemStat> EquipmentItemStats { get; private set; } = new();
public ItemAffix ItemAffix { get; private set; }
public ItemSetComponent ItemSet { get; private set; }
public event Action<PlayerAI> OnEquipEvent;
public event Action<PlayerAI> OnUnequipEvent;
public void Setup() { }
public EquipItem GetCopy() => Instantiate(this);
public void SetSlot(BaseItemSlot baseItemSlot) => ItemSlot = baseItemSlot;
public void ResetEquipmentItemStats() => EquipmentItemStats.Clear();
public void AddStatToEquipmentItemStats(EquipmentItemStat equipmentItemStat)
{
EquipmentItemStats.Add(equipmentItemStat);
EquipmentItemStats.Sort(SortIndex);
}
public int SortIndex(EquipmentItemStat x, EquipmentItemStat y)
{
if (x.playerStatType == PlayerStatType.MainStat) return -3;
if (y.playerStatType == PlayerStatType.MainStat) return 3;
if (x.playerStatType == PlayerStatType.Vitality) return -2;
if (y.playerStatType == PlayerStatType.Vitality) return 2;
if ((int)x.playerStatType < (int)y.playerStatType) return -1;
return 1;
}
public void AddItemAffix(ItemAffix itemAffix)
{
if (this.ItemAffix != null) return;
this.ItemAffix = itemAffix;
if (ItemAffix != null)
ItemAffix.SetItem(this);
}
public void AddItemSet(ItemSetComponent itemSet)
{
return;
/*
if (this.ItemSet != null) return;
ItemSet = itemSet;
if (ItemSet != null)
{
ItemSet.SetItem(this);
}
*/
}
public void Equip(PlayerStatsHolder playerStatsHolder)
{
if (playerStatsHolder == null) return;
this.PlayerStatsHolder = playerStatsHolder;
foreach (var stat in EquipmentItemStats)
{
playerStatsHolder.BuffStat(stat.playerStatType, stat.statValueType, stat.statValue);
}
OnEquipEvent?.Invoke(PlayerStatsHolder.PlayerAI);
}
public void Unequip()
{
if (PlayerStatsHolder != null)
{
foreach (var stat in EquipmentItemStats)
{
PlayerStatsHolder.DebuffStat(stat.playerStatType, stat.statValueType, stat.statValue);
}
OnUnequipEvent?.Invoke(PlayerStatsHolder.PlayerAI);
}
this.PlayerStatsHolder = null;
}
public bool IsHealerItem() => GameManager.Instance.IsHealer(playerClassType);
public void Destroy()
{
Destroy(this);
}
}
[System.Serializable]
public class EquipmentItemStat
{
public ItemStatType itemStatType;
public PlayerStatType playerStatType;
public StatValueType statValueType;
public ObscuredFloat statValue;
public ObscuredFloat minValue;
public ObscuredFloat maxValue;
}
#region --- Item Attributes---
public enum EquipmentType
{
Head,
Chest,
Shoulder,
Pants,
MainHand,
OffHand,
ExtraSlot,
None
}
public enum ItemRarity
{
Common,
Normal,
Rare,
Epic,
Legendary,
}
public enum MainHandType
{
Sword,
Axe,
Wand,
Staff,
Bow,
Dagger,
Hammer,
Scythe
}
public enum OffHandType
{
Gloves,
Book,
Bracers,
Quiver,
Shield,
Boots,
Amulett,
Belt,
}
#endregion
}
and any settings you've changed in the Settings window.
A long comment, hopefully you can read it through and see/explain what is wrong/what I can do better.
Thank you very much!