You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
324 lines
11 KiB
C#
324 lines
11 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Runtime.Serialization;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
namespace MoreMountains.Tools
|
|
{
|
|
/// <summary>
|
|
/// Add this component to a scene and it'll let you save and load the state of objects that implement the IMMPersistent interface
|
|
/// You can create your own classes that implement this interface, or use the MMPersistent class that comes with this package
|
|
/// It will save their transform data (position, rotation, scale) and their active state
|
|
/// Triggering save and load is done via events, and the manager also emits events every time data is loaded or saved
|
|
/// </summary>
|
|
public class MMPersistencyManager : MMPersistentSingleton<MMPersistencyManager>, MMEventListener<MMGameEvent>
|
|
{
|
|
[Header("Persistency")]
|
|
/// A persistency ID used to identify the data associated to this manager.
|
|
/// Usually you'll want to leave this to its default value.
|
|
[Tooltip("A persistency ID used to identify the data associated to this manager. Usually you'll want to leave this to its default value.")]
|
|
public string PersistencyID = "MMPersistency";
|
|
|
|
[Header("Events")]
|
|
/// whether or not this manager should listen for save events. If you set this to false, you'll have to call SaveToMemory or SaveFromMemoryToFile manually
|
|
[Tooltip("whether or not this manager should listen for save events. If you set this to false, you'll have to call SaveToMemory or SaveFromMemoryToFile manually")]
|
|
public bool ListenForSaveEvents = true;
|
|
/// whether or not this manager should listen for load events. If you set this to false, you'll have to call LoadFromMemory or LoadFromFileToMemory manually
|
|
[Tooltip("whether or not this manager should listen for load events. If you set this to false, you'll have to call LoadFromMemory or LoadFromFileToMemory manually")]
|
|
public bool ListenForLoadEvents = true;
|
|
/// whether or not this manager should listen for save to memory events. If you set this to false, you'll have to call SaveToMemory manually
|
|
[Tooltip("whether or not this manager should listen for save to memory events. If you set this to false, you'll have to call SaveToMemory manually")]
|
|
public bool ListenForSaveToMemoryEvents = true;
|
|
/// whether or not this manager should listen for load from memory events. If you set this to false, you'll have to call LoadFromMemory manually
|
|
[Tooltip("whether or not this manager should listen for load from memory events. If you set this to false, you'll have to call LoadFromMemory manually")]
|
|
public bool ListenForLoadFromMemoryEvents = true;
|
|
/// whether or not this manager should listen for save to file events. If you set this to false, you'll have to call SaveFromMemoryToFile manually
|
|
[Tooltip("whether or not this manager should listen for save to file events. If you set this to false, you'll have to call SaveFromMemoryToFile manually")]
|
|
public bool ListenForSaveToFileEvents = true;
|
|
/// whether or not this manager should listen for load from file events. If you set this to false, you'll have to call LoadFromFileToMemory manually
|
|
[Tooltip("whether or not this manager should listen for load from file events. If you set this to false, you'll have to call LoadFromFileToMemory manually")]
|
|
public bool ListenForLoadFromFileEvents = true;
|
|
/// whether or not this manager should save data to file on save events
|
|
[Tooltip("whether or not this manager should save data to file on save events")]
|
|
public bool SaveToFileOnSaveEvents = true;
|
|
/// whether or not this manager should load data from file on load events
|
|
[Tooltip("whether or not this manager should load data from file on load events")]
|
|
public bool LoadFromFileOnLoadEvents = true;
|
|
|
|
/// the debug buttons below are only meant to be used at runtime
|
|
[Header("Debug Buttons (Only at Runtime)")]
|
|
[MMInspectorButton("SaveToMemory")]
|
|
public bool SaveToMemoryButton;
|
|
[MMInspectorButton("LoadFromMemory")]
|
|
public bool LoadFromMemoryButton;
|
|
[MMInspectorButton("SaveFromMemoryToFile")]
|
|
public bool SaveToFileButton;
|
|
[MMInspectorButton("LoadFromFileToMemory")]
|
|
public bool LoadFromFileButton;
|
|
[MMInspectorButton("DeletePersistencyFile")]
|
|
public bool DeletePersistencyFileButton;
|
|
|
|
public DictionaryStringSceneData SceneDatas;
|
|
|
|
public static string _resourceItemPath = "Persistency/";
|
|
public static string _saveFolderName = "MMTools/";
|
|
public static string _saveFileExtension = ".persistency";
|
|
|
|
protected string _currentSceneName;
|
|
|
|
#region INITIALIZATION
|
|
|
|
/// <summary>
|
|
/// On Awake we initialize our dictionary
|
|
/// </summary>
|
|
protected override void Awake()
|
|
{
|
|
base.Awake();
|
|
SceneDatas = new DictionaryStringSceneData();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SAVE_AND_LOAD
|
|
|
|
/// <summary>
|
|
/// Saves data from objects that need saving to memory
|
|
/// </summary>
|
|
public virtual void SaveToMemory()
|
|
{
|
|
ComputeCurrentSceneName();
|
|
|
|
SceneDatas.Remove(_currentSceneName);
|
|
|
|
MMPersistencySceneData sceneData = new MMPersistencySceneData();
|
|
sceneData.ObjectDatas = new DictionaryStringString();
|
|
|
|
IMMPersistent[] persistents = FindAllPersistentObjects();
|
|
|
|
foreach (IMMPersistent persistent in persistents)
|
|
{
|
|
if (persistent.ShouldBeSaved())
|
|
{
|
|
sceneData.ObjectDatas.Add(persistent.GetGuid(), persistent.OnSave());
|
|
}
|
|
}
|
|
|
|
SceneDatas.Add(_currentSceneName, sceneData);
|
|
|
|
MMPersistencyEvent.Trigger(MMPersistencyEventType.DataSavedToMemory, PersistencyID);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads data from memory and applies it to all objects that need it
|
|
/// </summary>
|
|
public virtual void LoadFromMemory()
|
|
{
|
|
ComputeCurrentSceneName();
|
|
|
|
if (!SceneDatas.TryGetValue(_currentSceneName, out MMPersistencySceneData sceneData))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (sceneData.ObjectDatas == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
IMMPersistent[] persistents = FindAllPersistentObjects();
|
|
foreach (IMMPersistent persistent in persistents)
|
|
{
|
|
if (sceneData.ObjectDatas.TryGetValue(persistent.GetGuid(), out string data))
|
|
{
|
|
persistent.OnLoad(sceneData.ObjectDatas[persistent.GetGuid()]);
|
|
}
|
|
}
|
|
|
|
MMPersistencyEvent.Trigger(MMPersistencyEventType.DataLoadedFromMemory, PersistencyID);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Saves data from memory to a file
|
|
/// </summary>
|
|
public virtual void SaveFromMemoryToFile()
|
|
{
|
|
MMPersistencyManagerData saveData = new MMPersistencyManagerData();
|
|
saveData.PersistencyID = PersistencyID;
|
|
saveData.SaveDate = DateTime.Now.ToString();
|
|
saveData.SceneDatas = SceneDatas;
|
|
MMSaveLoadManager.Save(saveData, DetermineSaveName(), _saveFolderName);
|
|
|
|
MMPersistencyEvent.Trigger(MMPersistencyEventType.DataSavedFromMemoryToFile, PersistencyID);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads data from file and stores it in memory
|
|
/// </summary>
|
|
public virtual void LoadFromFileToMemory()
|
|
{
|
|
MMPersistencyManagerData saveData = (MMPersistencyManagerData)MMSaveLoadManager.Load(typeof(MMPersistencyManagerData), DetermineSaveName(), _saveFolderName);
|
|
if ((saveData != null) && (saveData.SceneDatas != null))
|
|
{
|
|
SceneDatas = new DictionaryStringSceneData();
|
|
SceneDatas = saveData.SceneDatas;
|
|
}
|
|
MMPersistencyEvent.Trigger(MMPersistencyEventType.DataLoadedFromFileToMemory, PersistencyID);
|
|
}
|
|
|
|
/// <summary>
|
|
/// On Save, we save to memory and to file if needed
|
|
/// </summary>
|
|
public virtual void Save()
|
|
{
|
|
SaveToMemory();
|
|
if (SaveToFileOnSaveEvents)
|
|
{
|
|
SaveFromMemoryToFile();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// On Load, we load from memory and from file if needed
|
|
/// </summary>
|
|
public virtual void Load()
|
|
{
|
|
if (LoadFromFileOnLoadEvents)
|
|
{
|
|
LoadFromFileToMemory();
|
|
}
|
|
LoadFromMemory();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RESET
|
|
|
|
/// <summary>
|
|
/// Deletes all persistency data for the specified scene
|
|
/// </summary>
|
|
/// <param name="sceneName"></param>
|
|
public virtual void DeletePersistencyMemoryForScene(string sceneName)
|
|
{
|
|
if (!SceneDatas.TryGetValue(_currentSceneName, out MMPersistencySceneData sceneData))
|
|
{
|
|
return;
|
|
}
|
|
SceneDatas.Remove(sceneName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deletes persistency data from memory and on file for this persistency manager
|
|
/// </summary>
|
|
public virtual void ResetPersistency()
|
|
{
|
|
DeletePersistencyMemory();
|
|
DeletePersistencyFile();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deletes all persistency data stored in this persistency manager's memory
|
|
/// </summary>
|
|
public virtual void DeletePersistencyMemory()
|
|
{
|
|
SceneDatas = new DictionaryStringSceneData();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deletes the save file for this persistency manager
|
|
/// </summary>
|
|
public virtual void DeletePersistencyFile()
|
|
{
|
|
MMSaveLoadManager.DeleteSave(DetermineSaveName(), _saveFolderName);
|
|
Debug.LogFormat("Persistency save file deleted");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region HELPERS
|
|
|
|
/// <summary>
|
|
/// Finds all objects in the scene that implement IMMPersistent and may need saving
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
protected virtual IMMPersistent[] FindAllPersistentObjects()
|
|
{
|
|
return FindObjectsOfType<MonoBehaviour>(true).OfType<IMMPersistent>().ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Grabs the current scene's name and stores it
|
|
/// </summary>
|
|
protected virtual void ComputeCurrentSceneName()
|
|
{
|
|
_currentSceneName = SceneManager.GetActiveScene().name;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines the name of the file to write to store persistency data
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
protected virtual string DetermineSaveName()
|
|
{
|
|
return gameObject.name + "_" + PersistencyID + _saveFileExtension;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region EVENTS
|
|
|
|
/// <summary>
|
|
/// When we get a MMEvent, we filter on its name and invoke the appropriate methods if needed
|
|
/// </summary>
|
|
/// <param name="gameEvent"></param>
|
|
public virtual void OnMMEvent(MMGameEvent gameEvent)
|
|
{
|
|
if ((gameEvent.EventName == "Save") && ListenForSaveEvents)
|
|
{
|
|
Save();
|
|
}
|
|
if ((gameEvent.EventName == "Load") && ListenForLoadEvents)
|
|
{
|
|
Load();
|
|
}
|
|
if ((gameEvent.EventName == "SaveToMemory") && ListenForSaveToMemoryEvents)
|
|
{
|
|
SaveToMemory();
|
|
}
|
|
if ((gameEvent.EventName == "LoadFromMemory") && ListenForLoadFromMemoryEvents)
|
|
{
|
|
LoadFromMemory();
|
|
}
|
|
if ((gameEvent.EventName == "SaveToFile") && ListenForSaveToFileEvents)
|
|
{
|
|
SaveFromMemoryToFile();
|
|
}
|
|
if ((gameEvent.EventName == "LoadFromFile") && ListenForLoadFromFileEvents)
|
|
{
|
|
LoadFromFileToMemory();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// On enable, we start listening for MMGameEvents
|
|
/// </summary>
|
|
protected virtual void OnEnable()
|
|
{
|
|
this.MMEventStartListening<MMGameEvent>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// On enable, we stop listening for MMGameEvents
|
|
/// </summary>
|
|
protected virtual void OnDisable()
|
|
{
|
|
this.MMEventStopListening<MMGameEvent>();
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|
|
|