UnityEssentials
Small but useful tools and features for Unity
SaveDataManager.cs
Go to the documentation of this file.
1 // MIT License
2 //
3 // Copyright (c) 2020 Bronson Zgeb
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 // SOFTWARE.
22 
23 
24 // Significant parts of the code are extracted from this GitHub repository: https://github.com/BayatGames/SaveGameFree and https://github.com/UnityTechnologies/UniteNow20-Persistent-Data
25 
26 
27 using System.IO;
28 using System.Text;
29 using Essentials.SaveData;
30 using UnityEditor;
31 
32 namespace UnityEngine
33 {
37  public static class SaveDataManager
38  {
39  public static string saveDataPath = Application.persistentDataPath;
40 
41  #if UNITY_EDITOR
46  [MenuItem("File/Open saves data folder", false, 300)]
47  #endif
48  public static void OpenSavedDataFolder()
49  {
50  #if UNITY_EDITOR
51  EditorUtility.RevealInFinder(saveDataPath);
52  #else
53  Debug.LogError("The folder containing the saved data can not be opened using the method OpenSavedDataFolder from the class SaveDataManager outside the Unity Editor.");
54  #endif
55  }
56 
57 
66  public static void Save<T>(T objectToSave, string filename, string encryptionPassword = null, Encoding encoding = null)
67  {
68  // Setup
69  SD_JsonSerializer serializer = new SD_JsonSerializer();
70  SD_Encoder encoder = new SD_Encoder();
71  encoding ??= Encoding.UTF8;
72  objectToSave ??= default(T);
73  if (string.IsNullOrEmpty(filename))
74  throw new System.ArgumentNullException(nameof(filename));
75  string filePath = GetFilePath(filename);
76 
77  // Build IO stream
78  Stream stream;
79  #if !UNITY_SAMSUNGTV && !UNITY_TVOS && !UNITY_WEBGL
80  #if UNITY_WSA || UNITY_WINRT
81  UnityEngine.Windows.Directory.CreateDirectory ( filePath );
82  #else
83  Directory.CreateDirectory(Path.GetDirectoryName(filePath) ?? string.Empty);
84  #endif
85  #endif
86  if (!encryptionPassword.IsNullEmptyOrWhiteSpace())
87  {
88  stream = new MemoryStream();
89  }
90  else
91  {
92  #if !UNITY_SAMSUNGTV && !UNITY_TVOS && !UNITY_WEBGL
93  if (Utils.IsIOSupported())
94  {
95  #if UNITY_WSA || UNITY_WINRT
96  stream = new MemoryStream ();
97  #else
98  stream = File.Create(filePath);
99  #endif
100  }
101  else
102  {
103  stream = new MemoryStream();
104  }
105  #else
106  stream = new MemoryStream ();
107  #endif
108  }
109 
110  // Serialize object
111  serializer.Serialize(objectToSave, stream, encoding);
112  if (!encryptionPassword.IsNullEmptyOrWhiteSpace())
113  {
114  string data = System.Convert.ToBase64String(((MemoryStream) stream).ToArray());
115  string encoded = encoder.Encode(data, encryptionPassword);
116  #if !UNITY_SAMSUNGTV && !UNITY_TVOS && !UNITY_WEBGL
117  if (Utils.IsIOSupported())
118  {
119  #if UNITY_WSA || UNITY_WINRT
120  UnityEngine.Windows.File.WriteAllBytes ( filePath, encoding.GetBytes ( encoded ) );
121  #else
122  File.WriteAllText(filePath, encoded, encoding);
123  #endif
124  }
125  else
126  {
127  PlayerPrefs.SetString(filePath, encoded);
128  PlayerPrefs.Save();
129  }
130  #else
131  PlayerPrefs.SetString ( filePath, encoded );
132  PlayerPrefs.Save ();
133  #endif
134  }
135  else if (!Utils.IsIOSupported())
136  {
137  string data = encoding.GetString(((MemoryStream) stream).ToArray());
138  PlayerPrefs.SetString(filePath, data);
139  PlayerPrefs.Save();
140  }
141  stream.Dispose();
142  }
143 
144  // ReSharper disable Unity.PerformanceAnalysis
154  public static T Load<T>(string filename, T defaultValue, string encryptionPassword = null, Encoding encoding = null, bool supressFileNotFoundWarning = false)
155  {
156  // Setup
157  SD_JsonSerializer serializer = new SD_JsonSerializer();
158  SD_Encoder encoder = new SD_Encoder();
159  encoding ??= Encoding.UTF8;
160  defaultValue ??= default(T);
161  if (string.IsNullOrEmpty(filename))
162  throw new System.ArgumentNullException(nameof(filename));
163  string filePath = GetFilePath(filename);
164  T result = defaultValue;
165 
166  #if !UNITY_SAMSUNGTV && !UNITY_TVOS && !UNITY_WEBGL
167  if (!Exists(filename))
168  #else
169  if ( !Exists ( filePath, path ) )
170  #endif
171  {
172  if (!supressFileNotFoundWarning)
173  Debug.LogWarning(
174  $"The file '{GetFilePath(filename)}' was not found. You can use the parameter 'supressFileNotFoundWarning' to disable the warning or use 'Exists()' to check if such file exists or not before trying to load them.\n" +
175  "Returning the default(T) instance."
176  );
177  return result;
178  }
179  Stream stream;
180  if (!encryptionPassword.IsNullEmptyOrWhiteSpace())
181  {
182  string data;
183  #if !UNITY_SAMSUNGTV && !UNITY_TVOS && !UNITY_WEBGL
184  if (Utils.IsIOSupported())
185  {
186  #if UNITY_WSA || UNITY_WINRT
187  data = encoding.GetString ( UnityEngine.Windows.File.ReadAllBytes ( filePath ) );
188  #else
189  data = File.ReadAllText(filePath, encoding);
190  #endif
191  }
192  else
193  {
194  data = PlayerPrefs.GetString(filePath);
195  }
196  #else
197  data = PlayerPrefs.GetString ( filePath );
198  #endif
199  string decoded = encoder.Decode(data, encryptionPassword);
200  stream = new MemoryStream(System.Convert.FromBase64String(decoded), true);
201  }
202  else
203  {
204  #if !UNITY_SAMSUNGTV && !UNITY_TVOS && !UNITY_WEBGL
205  if (Utils.IsIOSupported())
206  {
207  #if UNITY_WSA || UNITY_WINRT
208  stream = new MemoryStream ( UnityEngine.Windows.File.ReadAllBytes ( filePath ) );
209  #else
210  stream = File.OpenRead(filePath);
211  #endif
212  }
213  else
214  {
215  string data = PlayerPrefs.GetString(filePath);
216  stream = new MemoryStream(encoding.GetBytes(data));
217  }
218  #else
219  string data = PlayerPrefs.GetString ( filePath );
220  stream = new MemoryStream ( encoding.GetBytes ( data ) );
221  #endif
222  }
223  result = serializer.Deserialize<T>(stream, encoding);
224  stream.Dispose();
225  if (result == null)
226  {
227  result = defaultValue;
228  }
229  return result;
230  }
231 
236  public static bool Exists(string filename)
237  {
238  if (string.IsNullOrEmpty(filename))
239  {
240  throw new System.ArgumentNullException("filename");
241  }
242  string filePath = GetFilePath(filename);
243 
244  #if !UNITY_SAMSUNGTV && !UNITY_TVOS && !UNITY_WEBGL
245  if (Utils.IsIOSupported())
246  {
247  bool exists = false;
248  #if UNITY_WSA || UNITY_WINRT
249  exists = UnityEngine.Windows.Directory.Exists ( filePath );
250  #else
251  exists = Directory.Exists(filePath);
252  #endif
253  if (!exists)
254  {
255  #if UNITY_WSA || UNITY_WINRT
256  exists = UnityEngine.Windows.File.Exists ( filePath );
257  #else
258  exists = File.Exists(filePath);
259  #endif
260  }
261  return exists;
262  }
263  else
264  {
265  return PlayerPrefs.HasKey(filePath);
266  }
267  #else
268  return PlayerPrefs.HasKey ( filePath );
269  #endif
270  }
271 
272  private static string GetFilePath(string filename)
273  {
274 
275  return $"{saveDataPath}/{filename.Trim('/')}.json";
276  }
277 
282  public static void Delete(string filename)
283  {
284  if (string.IsNullOrEmpty(filename))
285  {
286  throw new System.ArgumentNullException(nameof(filename));
287  }
288  string filePath = GetFilePath(filename);
289 
290 #if !UNITY_SAMSUNGTV && !UNITY_TVOS && !UNITY_WEBGL
291  if (Utils.IsIOSupported())
292  {
293 #if UNITY_WSA || UNITY_WINRT
294  UnityEngine.Windows.File.Delete ( filePath );
295 #else
296  File.Delete(filePath);
297 #endif
298  }
299  else
300  {
301  PlayerPrefs.DeleteKey(filePath);
302  }
303 #else
304  PlayerPrefs.DeleteKey ( filePath );
305 #endif
306  }
307 
308 
313  public static void DeleteAll()
314  {
315  string dirPath = saveDataPath;
316 
317 #if !UNITY_SAMSUNGTV && !UNITY_TVOS && !UNITY_WEBGL
318  if (Utils.IsIOSupported())
319  {
320 #if UNITY_WSA || UNITY_WINRT
321  UnityEngine.Windows.Directory.Delete ( dirPath );
322 #else
323  DirectoryInfo info = new DirectoryInfo(dirPath);
324  FileInfo[] files = info.GetFiles();
325  for (int i = 0; i < files.Length; i++)
326  {
327  files[i].Delete();
328  }
329  DirectoryInfo[] dirs = info.GetDirectories();
330  for (int i = 0; i < dirs.Length; i++)
331  {
332  dirs[i].Delete(true);
333  }
334 #endif
335  }
336  else
337  {
338  PlayerPrefs.DeleteAll();
339  }
340 #else
341  PlayerPrefs.DeleteAll ();
342 #endif
343  }
344 
345  }
346 
347 }
A class to save almost any kind of data on almost all devices (not heavily tested).
static string GetFilePath(string filename)
static void Delete(string filename)
Delete the specified identifier and path.
static bool Exists(string filename)
Checks whether the specified identifier exists or not.
static void Save< T >(T objectToSave, string filename, string encryptionPassword=null, Encoding encoding=null)
Saves data using the identifier.
static void DeleteAll()
Deletes all.
static T Load< T >(string filename, T defaultValue, string encryptionPassword=null, Encoding encoding=null, bool supressFileNotFoundWarning=false)
Loads data using identifier.
Simple Encoder used by the SaveData class.
Definition: SD_Encoder.cs:41
string Decode(string input, string password)
Decode the specified input with password.
Definition: SD_Encoder.cs:92
string Encode(string input, string password)
Encode the specified input with password.
Definition: SD_Encoder.cs:51
Json Serializer used by the SaveData class.
A collection of useful methods that did not fit into any of the other sections of the asset.
Definition: Utils.cs:15
static bool IsIOSupported()
Checks if the IO is supported on current platform or not.
Definition: Utils.cs:147