chore: initial commit
This commit is contained in:
32
Assets/Feel/MMTools/Core/MMSaveLoad/IMMPersistent.cs
Normal file
32
Assets/Feel/MMTools/Core/MMSaveLoad/IMMPersistent.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
namespace MoreMountains.Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// An interface classes that want to be saved by the MMPersistencyManager need to implement
|
||||
/// </summary>
|
||||
public interface IMMPersistent
|
||||
{
|
||||
/// <summary>
|
||||
/// Needs to return a unique Guid used to identify this object
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
string GetGuid();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a savable string containing the object's data
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
string OnSave();
|
||||
|
||||
/// <summary>
|
||||
/// Loads the object's data from the passed string and applies it to its properties
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
void OnLoad(string data);
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not this object should be saved
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool ShouldBeSaved();
|
||||
}
|
||||
}
|
||||
11
Assets/Feel/MMTools/Core/MMSaveLoad/IMMPersistent.cs.meta
Normal file
11
Assets/Feel/MMTools/Core/MMSaveLoad/IMMPersistent.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 35d5d4d43a5ca4147b2488524fbe815e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MoreMountains.Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// A serializable class used to store scene data, the key is a string (the scene name), the value is a MMPersistencySceneData
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class DictionaryStringSceneData : MMSerializableDictionary<string, MMPersistenceSceneData>
|
||||
{
|
||||
public DictionaryStringSceneData() : base() { }
|
||||
protected DictionaryStringSceneData(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A serializable class used to store object data, the key is a string (the object name), the value is a string (the object data)
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class DictionaryStringString : MMSerializableDictionary<string, string>
|
||||
{
|
||||
public DictionaryStringString() : base() { }
|
||||
protected DictionaryStringString(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A serializable class used to store all the data for a persistence manager, a collection of scene datas
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class MMPersistenceManagerData
|
||||
{
|
||||
public string PersistenceID;
|
||||
public string SaveDate;
|
||||
public DictionaryStringSceneData SceneDatas;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A serializable class used to store all the data for a scene, a collection of object datas
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class MMPersistenceSceneData
|
||||
{
|
||||
public DictionaryStringString ObjectDatas;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The various types of persistence events that can be triggered by the MMPersistencyManager
|
||||
/// </summary>
|
||||
public enum MMPersistenceEventType { DataSavedToMemory, DataLoadedFromMemory, DataSavedFromMemoryToFile, DataLoadedFromFileToMemory }
|
||||
|
||||
/// <summary>
|
||||
/// A data structure used to store persistence event data.
|
||||
/// To use :
|
||||
/// MMPersistencyEvent.Trigger(MMPersistencyEventType.DataLoadedFromFileToMemory, "yourPersistencyID");
|
||||
/// </summary>
|
||||
public struct MMPersistenceEvent
|
||||
{
|
||||
public MMPersistenceEventType PersistenceEventType;
|
||||
public string PersistenceID;
|
||||
|
||||
public MMPersistenceEvent(MMPersistenceEventType eventType, string persistenceID)
|
||||
{
|
||||
PersistenceEventType = eventType;
|
||||
PersistenceID = persistenceID;
|
||||
}
|
||||
|
||||
static MMPersistenceEvent e;
|
||||
public static void Trigger(MMPersistenceEventType eventType, string persistencyID)
|
||||
{
|
||||
e.PersistenceEventType = eventType;
|
||||
e.PersistenceID = persistencyID;
|
||||
MMEventManager.TriggerEvent(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c89376b60a9ff4b4d922b8d35778d386
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
331
Assets/Feel/MMTools/Core/MMSaveLoad/MMPersistenceManager.cs
Normal file
331
Assets/Feel/MMTools/Core/MMSaveLoad/MMPersistenceManager.cs
Normal file
@@ -0,0 +1,331 @@
|
||||
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 MMPersistenceManager : MMPersistentSingleton<MMPersistenceManager>, MMEventListener<MMGameEvent>
|
||||
{
|
||||
[Header("Persistence")]
|
||||
/// A persistence ID used to identify the data associated to this manager.
|
||||
/// Usually you'll want to leave this to its default value.
|
||||
[Tooltip("A persistence ID used to identify the data associated to this manager. Usually you'll want to leave this to its default value.")]
|
||||
public string PersistenceID = "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("DeletePersistenceFile")]
|
||||
public bool DeletePersistenceFileButton;
|
||||
|
||||
public DictionaryStringSceneData SceneDatas;
|
||||
|
||||
public static string _resourceItemPath = "Persistence/";
|
||||
public static string _saveFolderName = "MMTools/";
|
||||
public static string _saveFileExtension = ".persistence";
|
||||
|
||||
protected string _currentSceneName;
|
||||
|
||||
#region INITIALIZATION
|
||||
/// <summary>
|
||||
/// Statics initialization to support enter play modes
|
||||
/// </summary>
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
protected static void InitializeStatics()
|
||||
{
|
||||
_instance = null;
|
||||
}
|
||||
|
||||
/// <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);
|
||||
|
||||
MMPersistenceSceneData sceneData = new MMPersistenceSceneData();
|
||||
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);
|
||||
|
||||
MMPersistenceEvent.Trigger(MMPersistenceEventType.DataSavedToMemory, PersistenceID);
|
||||
}
|
||||
|
||||
/// <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 MMPersistenceSceneData 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()]);
|
||||
}
|
||||
}
|
||||
|
||||
MMPersistenceEvent.Trigger(MMPersistenceEventType.DataLoadedFromMemory, PersistenceID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves data from memory to a file
|
||||
/// </summary>
|
||||
public virtual void SaveFromMemoryToFile()
|
||||
{
|
||||
MMPersistenceManagerData saveData = new MMPersistenceManagerData();
|
||||
saveData.PersistenceID = PersistenceID;
|
||||
saveData.SaveDate = DateTime.Now.ToString();
|
||||
saveData.SceneDatas = SceneDatas;
|
||||
MMSaveLoadManager.Save(saveData, DetermineSaveName(), _saveFolderName);
|
||||
|
||||
MMPersistenceEvent.Trigger(MMPersistenceEventType.DataSavedFromMemoryToFile, PersistenceID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads data from file and stores it in memory
|
||||
/// </summary>
|
||||
public virtual void LoadFromFileToMemory()
|
||||
{
|
||||
MMPersistenceManagerData saveData = (MMPersistenceManagerData)MMSaveLoadManager.Load(typeof(MMPersistenceManagerData), DetermineSaveName(), _saveFolderName);
|
||||
if ((saveData != null) && (saveData.SceneDatas != null))
|
||||
{
|
||||
SceneDatas = new DictionaryStringSceneData();
|
||||
SceneDatas = saveData.SceneDatas;
|
||||
}
|
||||
MMPersistenceEvent.Trigger(MMPersistenceEventType.DataLoadedFromFileToMemory, PersistenceID);
|
||||
}
|
||||
|
||||
/// <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 persistence data for the specified scene
|
||||
/// </summary>
|
||||
/// <param name="sceneName"></param>
|
||||
public virtual void DeletePersistencyMemoryForScene(string sceneName)
|
||||
{
|
||||
if (!SceneDatas.TryGetValue(_currentSceneName, out MMPersistenceSceneData sceneData))
|
||||
{
|
||||
return;
|
||||
}
|
||||
SceneDatas.Remove(sceneName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes persistence data from memory and on file for this persistence manager
|
||||
/// </summary>
|
||||
public virtual void ResetPersistence()
|
||||
{
|
||||
DeletePersistenceMemory();
|
||||
DeletePersistenceFile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all persistence data stored in this persistence manager's memory
|
||||
/// </summary>
|
||||
public virtual void DeletePersistenceMemory()
|
||||
{
|
||||
SceneDatas = new DictionaryStringSceneData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the save file for this persistence manager
|
||||
/// </summary>
|
||||
public virtual void DeletePersistenceFile()
|
||||
{
|
||||
MMSaveLoadManager.DeleteSave(DetermineSaveName(), _saveFolderName);
|
||||
Debug.LogFormat("Persistence 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 persistence data
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual string DetermineSaveName()
|
||||
{
|
||||
return gameObject.name + "_" + PersistenceID + _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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f66839a3914de3d4db7c5682fc89f2fe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
155
Assets/Feel/MMTools/Core/MMSaveLoad/MMPersistent.cs
Normal file
155
Assets/Feel/MMTools/Core/MMSaveLoad/MMPersistent.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace MoreMountains.Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// A persistent class that can save the essential parts of an object :
|
||||
/// its transform data (position, rotation, scale) and its active state
|
||||
/// This inherits from MMPersistentBase and implements the IMMPersistent interface
|
||||
/// It's a good example of how to implement the interface's OnSave and OnLoad methods
|
||||
/// </summary>
|
||||
public class MMPersistent : MMPersistentBase
|
||||
{
|
||||
|
||||
[Header("Properties")]
|
||||
/// whether or not to save this object's position
|
||||
[Tooltip("whether or not to save this object's position")]
|
||||
public bool SavePosition = true;
|
||||
/// whether or not to save this object's rotation
|
||||
[Tooltip("whether or not to save this object's rotation")]
|
||||
public bool SaveLocalRotation = true;
|
||||
/// whether or not to save this object's scale
|
||||
[Tooltip("whether or not to save this object's scale")]
|
||||
public bool SaveLocalScale = true;
|
||||
/// whether or not to save this object's active state
|
||||
[Tooltip("whether or not to save this object's active state")]
|
||||
public bool SaveActiveState = true;
|
||||
/// whether or not to save this object's components' enabled states
|
||||
[Tooltip("whether or not to save this object's components' enabled states")]
|
||||
public bool SaveEnabledStates = false;
|
||||
|
||||
/// <summary>
|
||||
/// A struct used to store and serialize the data we want to save
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct Data
|
||||
{
|
||||
public Vector3 Position;
|
||||
public Quaternion LocalRotation;
|
||||
public Vector3 LocalScale;
|
||||
public bool ActiveState;
|
||||
public List<ComponentData> ComponentEnabledStates;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct ComponentData
|
||||
{
|
||||
public string Name;
|
||||
public bool EnabledState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// On Save, we turn the object's transform data and active state to a Json string and return it to the MMPersistencyManager
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string OnSave()
|
||||
{
|
||||
List<ComponentData> saveEnabledStates = null;
|
||||
if (SaveEnabledStates)
|
||||
{
|
||||
saveEnabledStates = GetCurrentComponents();
|
||||
}
|
||||
return JsonUtility.ToJson(new Data { Position = this.transform.position,
|
||||
LocalRotation = this.transform.localRotation,
|
||||
LocalScale = this.transform.localScale,
|
||||
ActiveState = this.gameObject.activeSelf,
|
||||
ComponentEnabledStates = saveEnabledStates
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// On load, we read the saved json data and apply it to our object's properties
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
public override void OnLoad(string data)
|
||||
{
|
||||
if (SavePosition)
|
||||
{
|
||||
this.transform.position = JsonUtility.FromJson<Data>(data).Position;
|
||||
}
|
||||
|
||||
if (SaveLocalRotation)
|
||||
{
|
||||
this.transform.localRotation = JsonUtility.FromJson<Data>(data).LocalRotation;
|
||||
}
|
||||
|
||||
if (SaveLocalScale)
|
||||
{
|
||||
this.transform.localScale = JsonUtility.FromJson<Data>(data).LocalScale;
|
||||
}
|
||||
|
||||
if (SaveActiveState)
|
||||
{
|
||||
this.gameObject.SetActive(JsonUtility.FromJson<Data>(data).ActiveState);
|
||||
}
|
||||
|
||||
if (SaveEnabledStates)
|
||||
{
|
||||
List<ComponentData> loadedList = JsonUtility.FromJson<Data>(data).ComponentEnabledStates;
|
||||
|
||||
Behaviour[] components = gameObject.GetComponents<Behaviour>();
|
||||
Renderer[] renderers = gameObject.GetComponents<Renderer>();
|
||||
|
||||
if (loadedList.Count != components.Length + renderers.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
for (int i = 0; i < components.Length; i++)
|
||||
{
|
||||
if (loadedList[i].Name == components[i].name)
|
||||
{
|
||||
components[i].enabled = loadedList[i].EnabledState;
|
||||
}
|
||||
|
||||
total++;
|
||||
}
|
||||
|
||||
for (int j = 0; j < renderers.Length; j++)
|
||||
{
|
||||
if (loadedList[total+j].Name == renderers[j].name)
|
||||
{
|
||||
renderers[j].enabled = loadedList[total+j].EnabledState;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Grabs all components on this object
|
||||
/// </summary>
|
||||
protected virtual List<ComponentData> GetCurrentComponents()
|
||||
{
|
||||
List<ComponentData> currentComponents = new List<ComponentData>();
|
||||
Behaviour[] components = gameObject.GetComponents<Behaviour>();
|
||||
Renderer[] renderers = gameObject.GetComponents<Renderer>();
|
||||
foreach (Behaviour component in components)
|
||||
{
|
||||
currentComponents.Add(new ComponentData { Name = component.name, EnabledState = component.enabled });
|
||||
}
|
||||
foreach (Renderer renderer in renderers)
|
||||
{
|
||||
currentComponents.Add(new ComponentData { Name = renderer.name, EnabledState = renderer.enabled });
|
||||
}
|
||||
|
||||
return currentComponents;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
Assets/Feel/MMTools/Core/MMSaveLoad/MMPersistent.cs.meta
Normal file
11
Assets/Feel/MMTools/Core/MMSaveLoad/MMPersistent.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b0397bb261ecd924ba0668927c40ba3a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
141
Assets/Feel/MMTools/Core/MMSaveLoad/MMPersistentBase.cs
Normal file
141
Assets/Feel/MMTools/Core/MMSaveLoad/MMPersistentBase.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MoreMountains.Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class implementing the IMMPersistent interface, designed to be extended
|
||||
/// This mostly takes care of the GUID generation and validation
|
||||
/// </summary>
|
||||
[AddComponentMenu("")]
|
||||
public class MMPersistentBase : MonoBehaviour, IMMPersistent
|
||||
{
|
||||
[Header("Save")]
|
||||
/// whether or not this object should be saved
|
||||
[Tooltip("whether or not this object should be saved")]
|
||||
public bool SaveActive = true;
|
||||
|
||||
[Header("ID")]
|
||||
/// an optional suffix to add to the GUID, to make it more readable
|
||||
[Tooltip("an optional suffix to add to the GUID, to make it more readable")]
|
||||
public string UniqueIDSuffix;
|
||||
/// the object's unique ID
|
||||
[Tooltip("the object's unique ID")]
|
||||
[SerializeField]
|
||||
[MMReadOnly]
|
||||
protected string _guid;
|
||||
|
||||
/// a debug button used to force a new GUI generation
|
||||
[MMInspectorButton("GenerateGuid")]
|
||||
public bool GenerateGuidButton;
|
||||
|
||||
/// <summary>
|
||||
/// On validate, we make sure the object gets a valid GUID
|
||||
/// </summary>
|
||||
protected virtual void OnValidate()
|
||||
{
|
||||
ValidateGuid();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the object's GUID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual string GetGuid() => _guid;
|
||||
|
||||
/// <summary>
|
||||
/// Lets you set the object's GUID
|
||||
/// </summary>
|
||||
/// <param name="newGUID"></param>
|
||||
public virtual void SetGuid(string newGUID) => _guid = newGUID;
|
||||
|
||||
/// <summary>
|
||||
/// On save, does nothing, meant to be extended
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual string OnSave()
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// On load, does nothing, meant to be extended
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
public virtual void OnLoad(string data)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lets the persistence manager know whether or not the object should be saved
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual bool ShouldBeSaved()
|
||||
{
|
||||
return SaveActive;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a unique ID for the object, using the scene name, the object name, and a GUID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual string GenerateGuid()
|
||||
{
|
||||
string newGuid = Guid.NewGuid().ToString();
|
||||
|
||||
string guid =
|
||||
this.gameObject.scene.name
|
||||
+ "-"
|
||||
+ this.gameObject.name
|
||||
+ "-"
|
||||
+ newGuid;
|
||||
|
||||
if (!string.IsNullOrEmpty(UniqueIDSuffix))
|
||||
{
|
||||
guid += "-" + UniqueIDSuffix;
|
||||
}
|
||||
|
||||
this.SetGuid(guid);
|
||||
|
||||
return guid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the object's ID is unique or not
|
||||
/// </summary>
|
||||
/// <param name="guid"></param>
|
||||
/// <returns></returns>
|
||||
public virtual bool GuidIsUnique(string guid)
|
||||
{
|
||||
return Resources.FindObjectsOfTypeAll<MMPersistentBase>().Count(x => x.GetGuid() == guid) == 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the object's GUID, and generates a new one if needed, until a unique one is found
|
||||
/// </summary>
|
||||
public virtual void ValidateGuid()
|
||||
{
|
||||
if (!this.gameObject.scene.IsValid())
|
||||
{
|
||||
_guid = string.Empty;
|
||||
return;
|
||||
}
|
||||
|
||||
int maxCount = 1000;
|
||||
int i = 0;
|
||||
|
||||
while ( (string.IsNullOrEmpty(_guid) || !GuidIsUnique(_guid) ) && (i < maxCount) )
|
||||
{
|
||||
GenerateGuid();
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == maxCount)
|
||||
{
|
||||
Debug.LogWarning(this.gameObject.name + " couldn't generate a unique GUID after " + maxCount + " tries, you should probably change its UniqueIDSuffix");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
Assets/Feel/MMTools/Core/MMSaveLoad/MMPersistentBase.cs.meta
Normal file
11
Assets/Feel/MMTools/Core/MMSaveLoad/MMPersistentBase.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 161799775c19ed44495de8edf8935aa2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
199
Assets/Feel/MMTools/Core/MMSaveLoad/MMSaveLoadManager.cs
Normal file
199
Assets/Feel/MMTools/Core/MMSaveLoad/MMSaveLoadManager.cs
Normal file
@@ -0,0 +1,199 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace MoreMountains.Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows the save and load of objects in a specific folder and file.
|
||||
///
|
||||
/// How to use (at a minimum) :
|
||||
///
|
||||
/// Save : MMSaveLoadManager.Save(TestObject, FileName+SaveFileExtension, FolderName);
|
||||
///
|
||||
/// Load : TestObject = (YourObjectClass)MMSaveLoadManager.Load(typeof(YourObjectClass), FileName + SaveFileExtension, FolderName);
|
||||
///
|
||||
/// Delete save : MMSaveLoadManager.DeleteSave(FileName+SaveFileExtension, FolderName);
|
||||
///
|
||||
/// Delete save folder : MMSaveLoadManager.DeleteSaveFolder(FolderName);
|
||||
///
|
||||
/// You can also specify what IMMSaveLoadManagerMethod the system should use. By default it's binary but you can also pick binary encrypted, json, or json encrypted
|
||||
/// You'll find examples of how to set each of these in the MMSaveLoadTester class
|
||||
///
|
||||
/// </summary>
|
||||
public static class MMSaveLoadManager
|
||||
{
|
||||
/// the method to use when saving and loading files (has to be the same at both times of course)
|
||||
public static IMMSaveLoadManagerMethod SaveLoadMethod = new MMSaveLoadManagerMethodBinary();
|
||||
/// the default top level folder the system will use to save the file
|
||||
private const string _baseFolderName = "/MMData/";
|
||||
/// the name of the save folder if none is provided
|
||||
private const string _defaultFolderName = "MMSaveLoadManager";
|
||||
|
||||
/// <summary>
|
||||
/// Determines the save path to use when loading and saving a file based on a folder name.
|
||||
/// </summary>
|
||||
/// <returns>The save path.</returns>
|
||||
/// <param name="folderName">Folder name.</param>
|
||||
static string DetermineSavePath(string folderName = _defaultFolderName)
|
||||
{
|
||||
string savePath;
|
||||
// depending on the device we're on, we assemble the path
|
||||
if (Application.platform == RuntimePlatform.IPhonePlayer)
|
||||
{
|
||||
savePath = Application.persistentDataPath + _baseFolderName;
|
||||
}
|
||||
else
|
||||
{
|
||||
savePath = Application.persistentDataPath + _baseFolderName;
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
savePath = Application.dataPath + _baseFolderName;
|
||||
#endif
|
||||
|
||||
savePath = savePath + folderName + "/";
|
||||
return savePath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the name of the file to save
|
||||
/// </summary>
|
||||
/// <returns>The save file name.</returns>
|
||||
/// <param name="fileName">File name.</param>
|
||||
static string DetermineSaveFileName(string fileName)
|
||||
{
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save the specified saveObject, fileName and foldername into a file on disk.
|
||||
/// </summary>
|
||||
/// <param name="saveObject">Save object.</param>
|
||||
/// <param name="fileName">File name.</param>
|
||||
/// <param name="foldername">Foldername.</param>
|
||||
public static void Save(object saveObject, string fileName, string foldername = _defaultFolderName)
|
||||
{
|
||||
string savePath = DetermineSavePath(foldername);
|
||||
string saveFileName = DetermineSaveFileName(fileName);
|
||||
// if the directory doesn't already exist, we create it
|
||||
if (!Directory.Exists(savePath))
|
||||
{
|
||||
Directory.CreateDirectory(savePath);
|
||||
}
|
||||
// we serialize and write our object into a file on disk
|
||||
|
||||
FileStream saveFile = File.Create(savePath + saveFileName);
|
||||
|
||||
SaveLoadMethod.Save(saveObject, saveFile);
|
||||
saveFile.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load the specified file based on a file name into a specified folder
|
||||
/// </summary>
|
||||
/// <param name="fileName">File name.</param>
|
||||
/// <param name="foldername">Foldername.</param>
|
||||
public static object Load(System.Type objectType, string fileName, string foldername = _defaultFolderName)
|
||||
{
|
||||
string savePath = DetermineSavePath(foldername);
|
||||
string saveFileName = savePath + DetermineSaveFileName(fileName);
|
||||
|
||||
object returnObject;
|
||||
|
||||
// if the MMSaves directory or the save file doesn't exist, there's nothing to load, we do nothing and exit
|
||||
if (!Directory.Exists(savePath) || !File.Exists(saveFileName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
FileStream saveFile = File.Open(saveFileName, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
returnObject = SaveLoadMethod.Load(objectType, saveFile);
|
||||
saveFile.Close();
|
||||
|
||||
return returnObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a save from disk
|
||||
/// </summary>
|
||||
/// <param name="fileName">File name.</param>
|
||||
/// <param name="folderName">Folder name.</param>
|
||||
public static void DeleteSave(string fileName, string folderName = _defaultFolderName)
|
||||
{
|
||||
string savePath = DetermineSavePath(folderName);
|
||||
string saveFileName = DetermineSaveFileName(fileName);
|
||||
if (File.Exists(savePath + saveFileName))
|
||||
{
|
||||
File.Delete(savePath + saveFileName);
|
||||
}
|
||||
if (File.Exists(savePath + saveFileName + ".meta"))
|
||||
{
|
||||
File.Delete(savePath + saveFileName + ".meta");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the whole save folder
|
||||
/// </summary>
|
||||
/// <param name="folderName"></param>
|
||||
public static void DeleteSaveFolder(string folderName = _defaultFolderName)
|
||||
{
|
||||
string savePath = DetermineSavePath(folderName);
|
||||
if (Directory.Exists(savePath))
|
||||
{
|
||||
DeleteDirectory(savePath);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all save files saved by this MMSaveLoadManager
|
||||
/// </summary>
|
||||
public static void DeleteAllSaveFiles()
|
||||
{
|
||||
string savePath = DetermineSavePath("");
|
||||
|
||||
savePath = savePath.Substring(0, savePath.Length - 1);
|
||||
if (savePath.EndsWith("/"))
|
||||
{
|
||||
savePath = savePath.Substring(0, savePath.Length - 1);
|
||||
}
|
||||
|
||||
if (Directory.Exists(savePath))
|
||||
{
|
||||
DeleteDirectory(savePath);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the specified directory
|
||||
/// </summary>
|
||||
/// <param name="target_dir"></param>
|
||||
public static void DeleteDirectory(string target_dir)
|
||||
{
|
||||
string[] files = Directory.GetFiles(target_dir);
|
||||
string[] dirs = Directory.GetDirectories(target_dir);
|
||||
|
||||
foreach (string file in files)
|
||||
{
|
||||
File.SetAttributes(file, FileAttributes.Normal);
|
||||
File.Delete(file);
|
||||
}
|
||||
|
||||
foreach (string dir in dirs)
|
||||
{
|
||||
DeleteDirectory(dir);
|
||||
}
|
||||
|
||||
Directory.Delete(target_dir, false);
|
||||
|
||||
if (File.Exists(target_dir + ".meta"))
|
||||
{
|
||||
File.Delete(target_dir + ".meta");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aa3d0794b4f8e4b40b6a3dde5b794c0b
|
||||
timeCreated: 1478535356
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,61 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace MoreMountains.Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// This component, on Awake or on demand, will force a SaveLoadMethod on the MMSaveLoadManager, changing the way it saves data to file.
|
||||
/// This will impact all classes that use the MMSaveLoadManager (unless they change that method before saving or loading).
|
||||
/// If you change the method, your previously existing data files won't be compatible, you'll need to delete them and start with new ones.
|
||||
/// </summary>
|
||||
public class MMSaveLoadManagerMethod : MonoBehaviour
|
||||
{
|
||||
[Header("Save and load method")]
|
||||
[MMInformation("This component, on Awake or on demand, will force a SaveLoadMethod on the MMSaveLoadManager, changing the way it saves data to file. " +
|
||||
"This will impact all classes that use the MMSaveLoadManager (unless they change that method before saving or loading)." +
|
||||
"If you change the method, your previously existing data files won't be compatible, you'll need to delete them and start with new ones.",
|
||||
MMInformationAttribute.InformationType.Info,false)]
|
||||
|
||||
/// the method to use to save to file
|
||||
[Tooltip("the method to use to save to file")]
|
||||
public MMSaveLoadManagerMethods SaveLoadMethod = MMSaveLoadManagerMethods.Binary;
|
||||
/// the key to use to encrypt the file (if using an encryption method)
|
||||
[Tooltip("the key to use to encrypt the file (if using an encryption method)")]
|
||||
public string EncryptionKey = "ThisIsTheKey";
|
||||
|
||||
protected IMMSaveLoadManagerMethod _saveLoadManagerMethod;
|
||||
|
||||
/// <summary>
|
||||
/// On Awake, we set the MMSaveLoadManager's method to the chosen one
|
||||
/// </summary>
|
||||
protected virtual void Awake()
|
||||
{
|
||||
SetSaveLoadMethod();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new MMSaveLoadManagerMethod and passes it to the MMSaveLoadManager
|
||||
/// </summary>
|
||||
public virtual void SetSaveLoadMethod()
|
||||
{
|
||||
switch(SaveLoadMethod)
|
||||
{
|
||||
case MMSaveLoadManagerMethods.Binary:
|
||||
_saveLoadManagerMethod = new MMSaveLoadManagerMethodBinary();
|
||||
break;
|
||||
case MMSaveLoadManagerMethods.BinaryEncrypted:
|
||||
_saveLoadManagerMethod = new MMSaveLoadManagerMethodBinaryEncrypted();
|
||||
((MMSaveLoadManagerEncrypter)_saveLoadManagerMethod).Key = EncryptionKey;
|
||||
break;
|
||||
case MMSaveLoadManagerMethods.Json:
|
||||
_saveLoadManagerMethod = new MMSaveLoadManagerMethodJson();
|
||||
break;
|
||||
case MMSaveLoadManagerMethods.JsonEncrypted:
|
||||
_saveLoadManagerMethod = new MMSaveLoadManagerMethodJsonEncrypted();
|
||||
((MMSaveLoadManagerEncrypter)_saveLoadManagerMethod).Key = EncryptionKey;
|
||||
break;
|
||||
}
|
||||
MMSaveLoadManager.SaveLoadMethod = _saveLoadManagerMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b4d071b416837d40b9bab019b738769
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,43 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
|
||||
namespace MoreMountains.Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// This save load method saves and loads files as binary files
|
||||
/// </summary>
|
||||
public class MMSaveLoadManagerMethodBinary : IMMSaveLoadManagerMethod
|
||||
{
|
||||
/// <summary>
|
||||
/// Saves the specified object to disk at the specified location after serializing it
|
||||
/// </summary>
|
||||
/// <param name="objectToSave"></param>
|
||||
/// <param name="saveFile"></param>
|
||||
public void Save(object objectToSave, FileStream saveFile)
|
||||
{
|
||||
BinaryFormatter formatter = new BinaryFormatter();
|
||||
formatter.Serialize(saveFile, objectToSave);
|
||||
saveFile.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the specified file from disk and deserializes it
|
||||
/// </summary>
|
||||
/// <param name="objectType"></param>
|
||||
/// <param name="saveFile"></param>
|
||||
/// <returns></returns>
|
||||
public object Load(System.Type objectType, FileStream saveFile)
|
||||
{
|
||||
object savedObject;
|
||||
BinaryFormatter formatter = new BinaryFormatter();
|
||||
savedObject = formatter.Deserialize(saveFile);
|
||||
saveFile.Close();
|
||||
return savedObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 339f02b3d924b984db779a1af1a59be2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,60 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
|
||||
namespace MoreMountains.Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// This save load method saves and loads files as encrypted binary files
|
||||
/// </summary>
|
||||
public class MMSaveLoadManagerMethodBinaryEncrypted : MMSaveLoadManagerEncrypter, IMMSaveLoadManagerMethod
|
||||
{
|
||||
/// <summary>
|
||||
/// Saves the specified object to disk at the specified location after encrypting it
|
||||
/// </summary>
|
||||
/// <param name="objectToSave"></param>
|
||||
/// <param name="saveFile"></param>
|
||||
public void Save(object objectToSave, FileStream saveFile)
|
||||
{
|
||||
BinaryFormatter formatter = new BinaryFormatter();
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
formatter.Serialize(memoryStream, objectToSave);
|
||||
memoryStream.Position = 0;
|
||||
Encrypt(memoryStream, saveFile, Key);
|
||||
saveFile.Flush();
|
||||
memoryStream.Close();
|
||||
saveFile.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the specified file from disk, decrypts it, and deserializes it
|
||||
/// </summary>
|
||||
/// <param name="objectType"></param>
|
||||
/// <param name="saveFile"></param>
|
||||
/// <returns></returns>
|
||||
public object Load(System.Type objectType, FileStream saveFile)
|
||||
{
|
||||
object savedObject;
|
||||
BinaryFormatter formatter = new BinaryFormatter();
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
try
|
||||
{
|
||||
Decrypt(saveFile, memoryStream, Key);
|
||||
}
|
||||
catch (CryptographicException ce)
|
||||
{
|
||||
Debug.LogError("[MMSaveLoadManager] Encryption key error: " + ce.Message);
|
||||
return null;
|
||||
}
|
||||
memoryStream.Position = 0;
|
||||
savedObject = formatter.Deserialize(memoryStream);
|
||||
memoryStream.Close();
|
||||
saveFile.Close();
|
||||
return savedObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12d7216a3e967954ca8945932aa92fd4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,47 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace MoreMountains.Tools
|
||||
{
|
||||
public class MMSaveLoadManagerMethodJson : IMMSaveLoadManagerMethod
|
||||
{
|
||||
/// <summary>
|
||||
/// Saves the specified object at the specified location after converting it to json
|
||||
/// </summary>
|
||||
/// <param name="objectToSave"></param>
|
||||
/// <param name="saveFile"></param>
|
||||
public void Save(object objectToSave, FileStream saveFile)
|
||||
{
|
||||
string json = JsonUtility.ToJson(objectToSave);
|
||||
// if you prefer using NewtonSoft's JSON lib uncomment the line below and commment the line above
|
||||
//string json = Newtonsoft.Json.JsonConvert.SerializeObject(objectToSave);
|
||||
StreamWriter streamWriter = new StreamWriter(saveFile);
|
||||
streamWriter.Write(json);
|
||||
streamWriter.Close();
|
||||
saveFile.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the specified file and decodes it
|
||||
/// </summary>
|
||||
/// <param name="objectType"></param>
|
||||
/// <param name="saveFile"></param>
|
||||
/// <returns></returns>
|
||||
public object Load(System.Type objectType, FileStream saveFile)
|
||||
{
|
||||
object savedObject; // = System.Activator.CreateInstance(objectType);
|
||||
StreamReader streamReader = new StreamReader(saveFile, Encoding.UTF8);
|
||||
string json = streamReader.ReadToEnd();
|
||||
savedObject = JsonUtility.FromJson(json, objectType);
|
||||
// if you prefer using NewtonSoft's JSON lib uncomment the line below and commment the line above
|
||||
//savedObject = Newtonsoft.Json.JsonConvert.DeserializeObject(json,objectType);
|
||||
streamReader.Close();
|
||||
saveFile.Close();
|
||||
return savedObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 148ba46d50e5e7346a7ac051cf1b6617
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,64 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace MoreMountains.Tools
|
||||
{
|
||||
public class MMSaveLoadManagerMethodJsonEncrypted : MMSaveLoadManagerEncrypter, IMMSaveLoadManagerMethod
|
||||
{
|
||||
/// <summary>
|
||||
/// Saves the specified object at the specified location to disk, converts it to json and encrypts it
|
||||
/// </summary>
|
||||
/// <param name="objectToSave"></param>
|
||||
/// <param name="saveFile"></param>
|
||||
public void Save(object objectToSave, FileStream saveFile)
|
||||
{
|
||||
string json = JsonUtility.ToJson(objectToSave);
|
||||
// if you prefer using NewtonSoft's JSON lib uncomment the line below and commment the line above
|
||||
//string json = Newtonsoft.Json.JsonConvert.SerializeObject(objectToSave);
|
||||
using (MemoryStream memoryStream = new MemoryStream())
|
||||
using (StreamWriter streamWriter = new StreamWriter(memoryStream))
|
||||
{
|
||||
streamWriter.Write(json);
|
||||
streamWriter.Flush();
|
||||
memoryStream.Position = 0;
|
||||
Encrypt(memoryStream, saveFile, Key);
|
||||
}
|
||||
saveFile.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the specified file, decrypts it and decodes it
|
||||
/// </summary>
|
||||
/// <param name="objectType"></param>
|
||||
/// <param name="saveFile"></param>
|
||||
/// <returns></returns>
|
||||
public object Load(System.Type objectType, FileStream saveFile)
|
||||
{
|
||||
object savedObject = null;
|
||||
using (MemoryStream memoryStream = new MemoryStream())
|
||||
using (StreamReader streamReader = new StreamReader(memoryStream))
|
||||
{
|
||||
try
|
||||
{
|
||||
Decrypt(saveFile, memoryStream, Key);
|
||||
}
|
||||
catch (CryptographicException ce)
|
||||
{
|
||||
Debug.LogError("[MMSaveLoadManager] Encryption key error: " + ce.Message);
|
||||
return null;
|
||||
}
|
||||
memoryStream.Position = 0;
|
||||
savedObject = JsonUtility.FromJson(streamReader.ReadToEnd(), objectType);
|
||||
// if you prefer using NewtonSoft's JSON lib uncomment the line below and commment the line above
|
||||
//savedObject = Newtonsoft.Json.JsonConvert.DeserializeObject(sr.ReadToEnd(), objectType);
|
||||
}
|
||||
saveFile.Close();
|
||||
return savedObject;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b50f078655cbd34fb69ee48182dbf37
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,72 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace MoreMountains.Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// An interface to implement save and load using different methods (binary, json, etc)
|
||||
/// </summary>
|
||||
public interface IMMSaveLoadManagerMethod
|
||||
{
|
||||
void Save(object objectToSave, FileStream saveFile);
|
||||
object Load(System.Type objectType, FileStream saveFile);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The possible methods to save and load files to and from disk available in the MMSaveLoadManager
|
||||
/// </summary>
|
||||
public enum MMSaveLoadManagerMethods { Json, JsonEncrypted, Binary, BinaryEncrypted };
|
||||
|
||||
/// <summary>
|
||||
/// This class implements methods to encrypt and decrypt streams
|
||||
/// </summary>
|
||||
public abstract class MMSaveLoadManagerEncrypter
|
||||
{
|
||||
/// <summary>
|
||||
/// The Key to use to save and load the file
|
||||
/// </summary>
|
||||
public virtual string Key { get; set; } = "yourDefaultKey";
|
||||
|
||||
protected string _saltText = "SaltTextGoesHere";
|
||||
|
||||
/// <summary>
|
||||
/// Encrypts the specified input stream into the specified output stream using the key passed in parameters
|
||||
/// </summary>
|
||||
/// <param name="inputStream"></param>
|
||||
/// <param name="outputStream"></param>
|
||||
/// <param name="sKey"></param>
|
||||
protected virtual void Encrypt(Stream inputStream, Stream outputStream, string sKey)
|
||||
{
|
||||
RijndaelManaged algorithm = new RijndaelManaged();
|
||||
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sKey, Encoding.ASCII.GetBytes(_saltText));
|
||||
|
||||
algorithm.Key = key.GetBytes(algorithm.KeySize / 8);
|
||||
algorithm.IV = key.GetBytes(algorithm.BlockSize / 8);
|
||||
|
||||
CryptoStream cryptostream = new CryptoStream(inputStream, algorithm.CreateEncryptor(), CryptoStreamMode.Read);
|
||||
cryptostream.CopyTo(outputStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrypts the input stream into the output stream using the key passed in parameters
|
||||
/// </summary>
|
||||
/// <param name="inputStream"></param>
|
||||
/// <param name="outputStream"></param>
|
||||
/// <param name="sKey"></param>
|
||||
protected virtual void Decrypt(Stream inputStream, Stream outputStream, string sKey)
|
||||
{
|
||||
RijndaelManaged algorithm = new RijndaelManaged();
|
||||
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sKey, Encoding.ASCII.GetBytes(_saltText));
|
||||
|
||||
algorithm.Key = key.GetBytes(algorithm.KeySize / 8);
|
||||
algorithm.IV = key.GetBytes(algorithm.BlockSize / 8);
|
||||
|
||||
CryptoStream cryptostream = new CryptoStream(inputStream, algorithm.CreateDecryptor(), CryptoStreamMode.Read);
|
||||
cryptostream.CopyTo(outputStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b681190ef64d3e2438805b489a9ac9a4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1348
Assets/Feel/MMTools/Core/MMSaveLoad/MMSaveLoadTestScene.unity
Normal file
1348
Assets/Feel/MMTools/Core/MMSaveLoad/MMSaveLoadTestScene.unity
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a74b1b5d357902346825fdfd125ea399
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
118
Assets/Feel/MMTools/Core/MMSaveLoad/MMSaveLoadTester.cs
Normal file
118
Assets/Feel/MMTools/Core/MMSaveLoad/MMSaveLoadTester.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
#if MM_UI
|
||||
using UnityEngine.UI;
|
||||
#endif
|
||||
|
||||
namespace MoreMountains.Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// A test object to store data to test the MMSaveLoadManager class
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class MMSaveLoadTestObject
|
||||
{
|
||||
public string SavedText;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A simple class used in the MMSaveLoadTestScene to test the MMSaveLoadManager class
|
||||
/// </summary>
|
||||
public class MMSaveLoadTester : MonoBehaviour
|
||||
{
|
||||
[Header("Bindings")]
|
||||
#if MM_UI
|
||||
/// the text to save
|
||||
[Tooltip("the text to save")]
|
||||
public InputField TargetInputField;
|
||||
#endif
|
||||
|
||||
[Header("Save settings")]
|
||||
/// the chosen save method (json, encrypted json, binary, encrypted binary)
|
||||
[Tooltip("the chosen save method (json, encrypted json, binary, encrypted binary)")]
|
||||
public MMSaveLoadManagerMethods SaveLoadMethod = MMSaveLoadManagerMethods.Binary;
|
||||
/// the name of the file to save
|
||||
[Tooltip("the name of the file to save")]
|
||||
public string FileName = "TestObject";
|
||||
/// the name of the destination folder
|
||||
[Tooltip("the name of the destination folder")]
|
||||
public string FolderName = "MMTest/";
|
||||
/// the extension to use
|
||||
[Tooltip("the extension to use")]
|
||||
public string SaveFileExtension = ".testObject";
|
||||
/// the key to use to encrypt the file (if needed)
|
||||
[Tooltip("the key to use to encrypt the file (if needed)")]
|
||||
public string EncryptionKey = "ThisIsTheKey";
|
||||
|
||||
/// Test button
|
||||
[MMInspectorButton("Save")]
|
||||
public bool TestSaveButton;
|
||||
/// Test button
|
||||
[MMInspectorButton("Load")]
|
||||
public bool TestLoadButton;
|
||||
/// Test button
|
||||
[MMInspectorButton("Reset")]
|
||||
public bool TestResetButton;
|
||||
|
||||
protected IMMSaveLoadManagerMethod _saveLoadManagerMethod;
|
||||
|
||||
/// <summary>
|
||||
/// Saves the contents of the TestObject into a file
|
||||
/// </summary>
|
||||
public virtual void Save()
|
||||
{
|
||||
InitializeSaveLoadMethod();
|
||||
MMSaveLoadTestObject testObject = new MMSaveLoadTestObject();
|
||||
#if MM_UI
|
||||
testObject.SavedText = TargetInputField.text;
|
||||
#endif
|
||||
MMSaveLoadManager.Save(testObject, FileName+SaveFileExtension, FolderName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the saved data
|
||||
/// </summary>
|
||||
public virtual void Load()
|
||||
{
|
||||
InitializeSaveLoadMethod();
|
||||
MMSaveLoadTestObject testObject = (MMSaveLoadTestObject)MMSaveLoadManager.Load(typeof(MMSaveLoadTestObject), FileName + SaveFileExtension, FolderName);
|
||||
#if MM_UI
|
||||
TargetInputField.text = testObject.SavedText;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets all saves by deleting the whole folder
|
||||
/// </summary>
|
||||
protected virtual void Reset()
|
||||
{
|
||||
MMSaveLoadManager.DeleteSaveFolder(FolderName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new MMSaveLoadManagerMethod and passes it to the MMSaveLoadManager
|
||||
/// </summary>
|
||||
protected virtual void InitializeSaveLoadMethod()
|
||||
{
|
||||
switch(SaveLoadMethod)
|
||||
{
|
||||
case MMSaveLoadManagerMethods.Binary:
|
||||
_saveLoadManagerMethod = new MMSaveLoadManagerMethodBinary();
|
||||
break;
|
||||
case MMSaveLoadManagerMethods.BinaryEncrypted:
|
||||
_saveLoadManagerMethod = new MMSaveLoadManagerMethodBinaryEncrypted();
|
||||
(_saveLoadManagerMethod as MMSaveLoadManagerEncrypter).Key = EncryptionKey;
|
||||
break;
|
||||
case MMSaveLoadManagerMethods.Json:
|
||||
_saveLoadManagerMethod = new MMSaveLoadManagerMethodJson();
|
||||
break;
|
||||
case MMSaveLoadManagerMethods.JsonEncrypted:
|
||||
_saveLoadManagerMethod = new MMSaveLoadManagerMethodJsonEncrypted();
|
||||
(_saveLoadManagerMethod as MMSaveLoadManagerEncrypter).Key = EncryptionKey;
|
||||
break;
|
||||
}
|
||||
MMSaveLoadManager.SaveLoadMethod = _saveLoadManagerMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Feel/MMTools/Core/MMSaveLoad/MMSaveLoadTester.cs.meta
Normal file
11
Assets/Feel/MMTools/Core/MMSaveLoad/MMSaveLoadTester.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 58f9c048a89d0d5448bf5972cdc13fad
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user