using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using UnityEngine; namespace SUISS.Storage { public class Storage { static Storage() { Storage.storableAliases = new Dictionary(); Storage._lastFileSaveDateTime = new Dictionary(); foreach (Type type in Storage.GetAllTypes()) { object[] customAttributes = type.GetCustomAttributes(typeof(StorableAlias), true); if (customAttributes != null) { foreach (StorableAlias storableAlias in customAttributes) { if (string.IsNullOrEmpty(storableAlias.FullName)) { throw new Exception("Found a StorableAlias for " + type.FullName + " with a FullName that is null or an empty string."); } if (Storage.storableAliases.ContainsKey(storableAlias.FullName)) { throw new Exception(string.Concat(new string[] { "Duplicate StorableAlias found: ", storableAlias.FullName, " is registered as alias for both ", Storage.storableAliases[storableAlias.FullName].FullName, " and ", type.FullName, "." })); } Storage.storableAliases[storableAlias.FullName] = type; } } } Storage._storagePath = Application.persistentDataPath; } private Storage(StorageLifecycle lifecycle) { this._lifecycle = lifecycle; this._path = null; if (this._lifecycle != StorageLifecycle.Session) { this._path = "Storage"; if (this._lifecycle == StorageLifecycle.Purchases) { this._path = Path.Combine(this._path, "P"); } else if (this._lifecycle != StorageLifecycle.Forever) { this._path = Path.Combine(this._path, WWW.EscapeURL(Storage.currentPlayer)); if (this._lifecycle != StorageLifecycle.Player) { this._path = Path.Combine(this._path, "Game"); } } } this.Load(); } //[DebuggerBrowsable(DebuggerBrowsableState.Never)] public static event Action NewGameEvent; public static bool ShouldShowDiskFullWarning { get; private set; } public static string CurrentPlayer { get { return Storage.currentPlayer; } } private static Type[] GetAllTypes() { return Assembly.GetExecutingAssembly().GetTypes(); } public static Storage Get(StorageLifecycle lifecycle) { if (lifecycle < StorageLifecycle.Forever) { return null; } while (lifecycle >= (StorageLifecycle)Storage.storageCache.Count) { Storage.storageCache.Add(null); } if (Storage.storageCache[(int)lifecycle] == null) { Storage.storageCache[(int)lifecycle] = new Storage(lifecycle); } return Storage.storageCache[(int)lifecycle]; } public static void ChangePlayer(string player, bool deleteOld) { if (player == null) { throw new ArgumentException("Player can't be null.", "player"); } if (deleteOld) { Storage storage = Storage.Get(StorageLifecycle.Player); storage.Delete(); } Storage.storageCache[1] = null; Storage.currentPlayer = player; } public static void NewGame() { Storage storage = Storage.Get(StorageLifecycle.Game); storage.Delete(); Storage.storageCache[2] = null; if (Storage.NewGameEvent != null) { Storage.NewGameEvent(); } } public static void NewSession() { Storage storage = Storage.Get(StorageLifecycle.Session); storage.Delete(); Storage.storageCache[3] = null; } public static void SaveAll(bool obsolete = false) { Storage.Save(Storage.storageCache); } public static void Save(IEnumerable storages) { Dictionary> dictionary = new Dictionary>(); foreach (Storage storage in storages) { if (storage != null && storage._path != null) { bool flag; string key = storage.FindSaveFile(out flag); dictionary[key] = storage.Root; storage.DeleteOldVersions((!flag) ? 0 : -1); } } foreach (string text in dictionary.Keys) { Dictionary dictionary2 = dictionary[text]; Exception arg = null; string text2 = Path.Combine(Storage._storagePath, text); if (!Storage.SaveDictionary(dictionary2, text2, out arg)) { string message = string.Format("Unable to save dictionary to {0}: {1}", text, arg); UnityEngine.Debug.LogError(message); DateTime dateTime; string text3 = (!Storage._lastFileSaveDateTime.TryGetValue(text2, out dateTime)) ? "Never" : dateTime.ToString("yyyy-MM-dd HH:mm:ss.fff"); UnityEngine.Debug.LogErrorFormat("[Unable to save {0}] Previous save time: {1} ; Current time: {2}", new object[] { text, text3, DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff") }); } else { Storage._lastFileSaveDateTime[text2] = DateTime.UtcNow; } } } public static void SaveLifecycle(StorageLifecycle lifecycle, bool obsolete = false) { Storage.Save(new List { Storage.Get(lifecycle) }); } public static Dictionary LoadDictionary(string filename) { Dictionary result = null; if (filename != null && File.Exists(filename)) { try { using (Stream stream = File.Open(filename, FileMode.Open, FileAccess.Read)) { result = (Dictionary)Storage.DeserializeObject(stream, new byte[20], new List()); } } catch (Exception ex) { UnityEngine.Debug.LogErrorFormat("Unable to load dictionary to {0}: {1}", new object[] { filename, ex.ToString() }); } } return result; } public static bool ExceptionMeansFullDisk(Exception ex) { return ex != null && !string.IsNullOrEmpty(ex.Message) && ex.Message.ToLower().Contains("disk full"); } public static bool SaveDictionary(Dictionary dictionary, string filename, out Exception outException) { outException = null; if (filename == null || dictionary == null) { return false; } try { string directoryName = Path.GetDirectoryName(filename); if (directoryName != null && !Directory.Exists(directoryName)) { Directory.CreateDirectory(directoryName); } } catch (Exception innerException) { outException = new Exception("Directory creation failed.", innerException); return false; } string text = Path.Combine(Path.GetDirectoryName(filename), "tmp_" + Path.GetFileName(filename)); Stream stream = null; try { stream = File.Open(text, FileMode.Create, FileAccess.Write); Storage.SerializeObject(stream, dictionary, new byte[20], new Dictionary()); } catch (Exception ex) { if (Storage.ExceptionMeansFullDisk(ex) || Storage.ExceptionMeansFullDisk(ex.InnerException)) { Storage.ShowDiskFullWarning(); } outException = new Exception("Stream opening & writing failed.", ex); return false; } finally { try { stream.Dispose(); } catch (Exception) { } } if (File.Exists(filename)) { try { File.Delete(filename); } catch (Exception innerException2) { outException = new Exception("Existing save file removal failed.", innerException2); return false; } } try { File.Move(text, filename); } catch (Exception innerException3) { outException = new Exception("Temporary file renaming failed.", innerException3); return false; } return true; } public static Dictionary CloneDictionary(Dictionary dictionary) { if (dictionary == null) { return null; } Dictionary dictionary2 = new Dictionary(dictionary.Count); foreach (KeyValuePair keyValuePair in dictionary) { dictionary2[keyValuePair.Key] = Storage.CloneObject(keyValuePair.Value); } return dictionary2; } public static List CloneList(List list) { if (list == null) { return null; } List list2 = new List(list.Count); foreach (object o in list) { list2.Add(Storage.CloneObject(o)); } return list2; } public static object[] CloneArray(object[] array) { if (array == null) { return null; } object[] array2 = new object[array.Length]; for (int i = 0; i < array.Length; i++) { array2[i] = Storage.CloneObject(array[i]); } return array2; } public static IStorable CloneIStorable(IStorable storable) { if (storable == null) { return null; } IDictionary dict = storable.ToStorage(); Type type = storable.GetType(); ConstructorInfo constructor = type.GetConstructor(new Type[0]); if (constructor == null) { throw new FormatException("Type " + type.AssemblyQualifiedName + " does not have an empty constructor."); } IStorable storable2 = (IStorable)constructor.Invoke(null); storable2.FromStorage(dict); return storable2; } public static object CloneObject(object o) { if (o is Dictionary) { return Storage.CloneDictionary((Dictionary)o); } if (o is List) { return Storage.CloneList((List)o); } if (o is object[]) { return Storage.CloneArray((object[])o); } if (o is ICloneable) { return ((ICloneable)o).Clone(); } if (o is IStorable) { return Storage.CloneIStorable((IStorable)o); } if (o != null && !o.GetType().IsValueType) { UnityEngine.Debug.LogErrorFormat("\"Cloning\" type {0}", new object[] { o.GetType() }); } return o; } public static bool VerifyType(object o) { return Storage.VerifyType(o, false); } public static bool VerifyType(object o, bool throwException) { if (object.ReferenceEquals(o, null) || o is Dictionary || o is List || o is object[] || o is string || o is bool || o is char || o is float || o is double || o is sbyte || o is byte || o is short || o is ushort || o is int || o is uint || o is long || o is ulong || o is decimal || o is IStorable) { return true; } if (throwException) { throw new ArgumentException(string.Concat(new object[] { "Value ", o, " of type ", o.GetType().AssemblyQualifiedName, " is not a storable type." })); } return false; } public static string DictToString(Dictionary storage) { string result; using (Stream stream = new MemoryStream()) { Storage.SerializeObject(stream, storage, new byte[20], new Dictionary()); stream.Flush(); stream.Position = 0L; string text = Convert.ToBase64String(Storage.ReadFully(stream)); result = text; } return result; } public static Dictionary StringToDict(string input) { byte[] buffer = Convert.FromBase64String(input); Dictionary result; using (MemoryStream memoryStream = new MemoryStream(buffer)) { memoryStream.Flush(); memoryStream.Position = 0L; result = (Dictionary)Storage.DeserializeObject(memoryStream, new byte[20], new List()); } return result; } public static bool UnityVersionIsAtLeast(string version, int major, int minor, int revision, int patch) { Regex regex = new Regex("^([0-9]+)\\.([0-9]+)\\.([0-9]+)(?:(.)([0-9]+))?$", RegexOptions.CultureInvariant); Match match = regex.Match(version); if (!match.Success) { return true; } int num = int.Parse(match.Groups[1].ToString()); int num2 = int.Parse(match.Groups[2].ToString()); int num3 = int.Parse(match.Groups[3].ToString()); int num4 = (!match.Groups[5].Success) ? 0 : int.Parse(match.Groups[5].ToString()); if (num != major) { return num > major; } if (num2 != minor) { return num2 > minor; } if (num3 != revision) { return num3 > revision; } return num4 >= patch; } private static object DeserializeObject(Stream stream, byte[] buffer, List stringTable) { int num = stream.ReadByte(); if (num < 0) { throw new FormatException("Unexpected end of stream."); } char c = (char)num; if (c == 'n') { return null; } if (c == '{') { int num2 = (int)Storage.ReadLength(stream); Dictionary dictionary = new Dictionary(num2); for (int i = 0; i < num2; i++) { string key = (string)Storage.DeserializeObject(stream, buffer, stringTable); object value = Storage.DeserializeObject(stream, buffer, stringTable); dictionary.Add(key, value); } return dictionary; } if (c == '[') { int num3 = (int)Storage.ReadLength(stream); List list = new List(); for (int j = 0; j < num3; j++) { object item = Storage.DeserializeObject(stream, buffer, stringTable); list.Add(item); } return list; } if (c == ']') { int num4 = (int)Storage.ReadLength(stream); object[] array = new object[num4]; for (int k = 0; k < num4; k++) { array[k] = Storage.DeserializeObject(stream, buffer, stringTable); } return array; } if (c == '$') { int num5 = (int)Storage.ReadLength(stream); byte[] array2 = new byte[num5]; if (stream.Read(array2, 0, num5) != num5) { throw new FormatException("Unexpected end of stream."); } string @string = Encoding.UTF8.GetString(array2, 0, array2.Length); stringTable.Add(@string); return @string; } else if (c == '#') { int num6 = (int)Storage.ReadLength(stream); if (num6 < 0 || num6 >= stringTable.Count) { throw new FormatException("String table index out of bounds."); } return stringTable[num6]; } else if (c == '@') { string text = (string)Storage.DeserializeObject(stream, buffer, stringTable); Dictionary dictionary2 = (Dictionary)Storage.DeserializeObject(stream, buffer, stringTable); string typeFullName = Storage.GetTypeFullName(text); Type type; if (Storage.storableAliases.ContainsKey(typeFullName)) { type = Storage.storableAliases[typeFullName]; } else { type = Type.GetType(text); if (type == null) { UnityEngine.Debug.LogError(string.Format("Unable to find type {0} while deserializing. Will return Dictionary instead.", text)); return dictionary2; } } ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes); object obj; if (constructor == null) { obj = Activator.CreateInstance(type); } else { obj = constructor.Invoke(null); } if (obj == null) { throw new FormatException("Type " + text + " does not have an empty constructor; nor is it a struct with default constructor."); } ((IStorable)obj).FromStorage(dictionary2); return obj; } else { if (c == '1') { return true; } if (c == '0') { return false; } if (c == 'c') { if (stream.Read(buffer, 0, 2) != 2) { throw new FormatException("Unexpected end of stream."); } return (char)((int)buffer[0] << 8 | (int)buffer[1]); } else { if (c == 'f') { Storage.UIntToFloat uintToFloat = default(Storage.UIntToFloat); uintToFloat.UIntValue = Storage.ReadInt(stream, buffer); return uintToFloat.FloatValue; } if (c == 'd') { uint num7 = Storage.ReadInt(stream, buffer); uint num8 = Storage.ReadInt(stream, buffer); return BitConverter.Int64BitsToDouble((long)((ulong)num7 << 32 | (ulong)num8)); } if (c == 'b') { int num9 = stream.ReadByte(); if (num9 < 0) { throw new FormatException("Unexpected end of stream."); } return (sbyte)num9; } else if (c == 'B') { int num10 = stream.ReadByte(); if (num10 < 0) { throw new FormatException("Unexpected end of stream."); } return (byte)num10; } else if (c == 's') { if (stream.Read(buffer, 0, 2) != 2) { throw new FormatException("Unexpected end of stream."); } return (short)((int)buffer[0] << 8 | (int)buffer[1]); } else if (c == 'S') { if (stream.Read(buffer, 0, 2) != 2) { throw new FormatException("Unexpected end of stream."); } return (ushort)((int)buffer[0] << 8 | (int)buffer[1]); } else { if (c == 'i') { return (int)Storage.ReadInt(stream, buffer); } if (c == 'I') { return Storage.ReadInt(stream, buffer); } if (c == 'l') { if (stream.Read(buffer, 0, 8) != 8) { throw new FormatException("Unexpected end of stream."); } return (long)((ulong)buffer[0] << 56 | (ulong)buffer[1] << 48 | (ulong)buffer[2] << 40 | (ulong)buffer[3] << 32 | (ulong)buffer[4] << 24 | (ulong)buffer[5] << 16 | (ulong)buffer[6] << 8 | (ulong)buffer[7]); } else if (c == 'L') { if (stream.Read(buffer, 0, 8) != 8) { throw new FormatException("Unexpected end of stream."); } return (ulong)buffer[0] << 56 | (ulong)buffer[1] << 48 | (ulong)buffer[2] << 40 | (ulong)buffer[3] << 32 | (ulong)buffer[4] << 24 | (ulong)buffer[5] << 16 | (ulong)buffer[6] << 8 | (ulong)buffer[7]; } else { if (c == 'a') { int[] array3 = new int[4]; for (int l = 0; l < 4; l++) { array3[l] = (int)Storage.ReadInt(stream, buffer); } return new decimal(array3); } throw new FormatException("Unknown type (" + c + ") encountered."); } } } } } private static void SerializeObject(Stream stream, object o, byte[] buffer, Dictionary stringTable) { try { if (object.ReferenceEquals(o, null)) { stream.WriteByte(110); } else if (o is Dictionary) { Dictionary dictionary = (Dictionary)o; stream.WriteByte(123); WriteLength(stream, (uint)dictionary.Count, buffer); foreach (KeyValuePair item in dictionary) { SerializeObject(stream, item.Key, buffer, stringTable); SerializeObject(stream, item.Value, buffer, stringTable); } } else if (o is List) { List list = (List)o; stream.WriteByte(91); WriteLength(stream, (uint)list.Count, buffer); foreach (object item2 in list) { SerializeObject(stream, item2, buffer, stringTable); } } else if (o is object[]) { object[] array = (object[])o; stream.WriteByte(93); WriteLength(stream, (uint)array.Length, buffer); object[] array2 = array; foreach (object o2 in array2) { SerializeObject(stream, o2, buffer, stringTable); } } else if (o is string) { string text = (string)o; uint value; if (stringTable.TryGetValue(text, out value)) { stream.WriteByte(35); WriteLength(stream, value, buffer); } else { byte[] bytes = Encoding.UTF8.GetBytes(text); stream.WriteByte(36); WriteLength(stream, (uint)bytes.Length, buffer); stream.Write(bytes, 0, bytes.Length); stringTable[text] = (uint)stringTable.Count; } } else if (o is bool) { if ((bool)o) { stream.WriteByte(49); } else { stream.WriteByte(48); } } else if (o is char) { int num = (char)o; buffer[0] = 99; buffer[1] = (byte)(num >> 8); buffer[2] = (byte)(num & 0xFF); stream.Write(buffer, 0, 3); } else if (o is float) { UIntToFloat uIntToFloat = default(UIntToFloat); uIntToFloat.FloatValue = (float)o; stream.WriteByte(102); WriteInt(stream, uIntToFloat.UIntValue, buffer); } else if (o is double) { ulong num2 = (ulong)BitConverter.DoubleToInt64Bits((double)o); stream.WriteByte(100); WriteInt(stream, (uint)(num2 >> 32), buffer); WriteInt(stream, (uint)(num2 & uint.MaxValue), buffer); } else if (o is sbyte) { byte b = (byte)(sbyte)o; buffer[0] = 98; buffer[1] = b; stream.Write(buffer, 0, 2); } else if (o is byte) { byte b2 = (byte)o; buffer[0] = 66; buffer[1] = b2; stream.Write(buffer, 0, 2); } else if (o is short) { uint num3 = (uint)(short)o; buffer[0] = 115; buffer[1] = (byte)(num3 >> 8); buffer[2] = (byte)(num3 & 0xFF); stream.Write(buffer, 0, 3); } else if (o is ushort) { uint num4 = (ushort)o; buffer[0] = 83; buffer[1] = (byte)(num4 >> 8); buffer[2] = (byte)(num4 & 0xFF); stream.Write(buffer, 0, 3); } else if (o is int) { uint num5 = (uint)(int)o; buffer[0] = 105; buffer[1] = (byte)(num5 >> 24); buffer[2] = (byte)((num5 >> 16) & 0xFF); buffer[3] = (byte)((num5 >> 8) & 0xFF); buffer[4] = (byte)(num5 & 0xFF); stream.Write(buffer, 0, 5); } else if (o is uint) { uint num6 = (uint)o; buffer[0] = 73; buffer[1] = (byte)(num6 >> 24); buffer[2] = (byte)((num6 >> 16) & 0xFF); buffer[3] = (byte)((num6 >> 8) & 0xFF); buffer[4] = (byte)(num6 & 0xFF); stream.Write(buffer, 0, 5); } else if (o is long) { ulong num7 = (ulong)(long)o; buffer[0] = 108; buffer[1] = (byte)(num7 >> 56); buffer[2] = (byte)((num7 >> 48) & 0xFF); buffer[3] = (byte)((num7 >> 40) & 0xFF); buffer[4] = (byte)((num7 >> 32) & 0xFF); buffer[5] = (byte)((num7 >> 24) & 0xFF); buffer[6] = (byte)((num7 >> 16) & 0xFF); buffer[7] = (byte)((num7 >> 8) & 0xFF); buffer[8] = (byte)(num7 & 0xFF); stream.Write(buffer, 0, 9); } else if (o is ulong) { ulong num8 = (ulong)o; buffer[0] = 76; buffer[1] = (byte)(num8 >> 56); buffer[2] = (byte)((num8 >> 48) & 0xFF); buffer[3] = (byte)((num8 >> 40) & 0xFF); buffer[4] = (byte)((num8 >> 32) & 0xFF); buffer[5] = (byte)((num8 >> 24) & 0xFF); buffer[6] = (byte)((num8 >> 16) & 0xFF); buffer[7] = (byte)((num8 >> 8) & 0xFF); buffer[8] = (byte)(num8 & 0xFF); stream.Write(buffer, 0, 9); } else if (o is decimal) { decimal d = (decimal)o; stream.WriteByte(97); int[] bits = decimal.GetBits(d); for (int j = 0; j < 4; j++) { WriteInt(stream, (uint)bits[j], buffer); } } else { if (!(o is IStorable)) { throw new FormatException("Can't serialize object " + o.ToString() + " because it does not implement IStorable."); } stream.WriteByte(64); SerializeObject(stream, o.GetType().AssemblyQualifiedName, buffer, stringTable); SerializeObject(stream, ((IStorable)o).ToStorage(), buffer, stringTable); } } catch (CaughtException) { throw; } catch (Exception ex2) { string message = string.Format("SerializeObject exception of object of type {0}", (o != null) ? o.GetType().ToString() : "null"); throw new CaughtException(message, ex2); } } private static void WriteLength(Stream stream, uint length, byte[] buffer) { int count = 0; uint num; for (num = length; num >= 128u; num >>= 7) { buffer[count++] = (byte)(128u | (num & 127u)); } buffer[count++] = (byte)num; stream.Write(buffer, 0, count); } private static uint ReadLength(Stream stream) { uint num = 0u; int num2 = 0; int num3; while ((num3 = stream.ReadByte()) >= 128) { if (num2 >= 4) { throw new FormatException("Invalid length."); } num |= (uint)((uint)(num3 & 127) << num2 * 7); num2++; } if (num3 < 0) { throw new FormatException("Unexpected end of stream."); } return num | (uint)((uint)num3 << num2 * 7); } private static void WriteInt(Stream stream, uint i, byte[] buffer) { buffer[0] = (byte)(i >> 24); buffer[1] = (byte)(i >> 16 & 255u); buffer[2] = (byte)(i >> 8 & 255u); buffer[3] = (byte)(i & 255u); stream.Write(buffer, 0, 4); } private static uint ReadInt(Stream stream, byte[] buffer) { int num = stream.Read(buffer, 0, 4); if (num != 4) { throw new FormatException("Unexpected end of stream."); } return (uint)((int)buffer[0] << 24 | (int)buffer[1] << 16 | (int)buffer[2] << 8 | (int)buffer[3]); } private static void ShowDiskFullWarning() { Storage.ShouldShowDiskFullWarning = true; } private static string GetTypeFullName(string assemblyQualifiedName) { int num = assemblyQualifiedName.IndexOf(','); if (num >= 0) { return assemblyQualifiedName.Substring(0, num); } return assemblyQualifiedName; } private static byte[] ReadFully(Stream stream) { byte[] array = new byte[32768]; byte[] result; using (MemoryStream memoryStream = new MemoryStream()) { for (; ; ) { int num = stream.Read(array, 0, array.Length); if (num <= 0) { break; } memoryStream.Write(array, 0, num); } result = memoryStream.ToArray(); } return result; } //[DebuggerBrowsable(DebuggerBrowsableState.Never)] public event Storage.OnSyncHandler OnSync; public StorageLifecycle Lifecycle { get { return this._lifecycle; } } public Dictionary Root { get { if (this.OnSync != null) { this.OnSync(); } return this._root; } } public DateTime CreationTimestamp { get { object obj; if (this._root.TryGetValue("~Creation~", out obj)) { return new DateTime((long)obj, DateTimeKind.Utc); } return DateTime.MinValue; } private set { if (value.Kind != DateTimeKind.Utc) { value = value.ToUniversalTime(); } this._root["~Creation~"] = value.Ticks; } } public DateTime UpdateTimestamp { get { object obj; if (this._root.TryGetValue("~Update~", out obj)) { return new DateTime((long)obj, DateTimeKind.Utc); } return DateTime.MinValue; } private set { if (value.Kind != DateTimeKind.Utc) { value = value.ToUniversalTime(); } this._root["~Update~"] = value.Ticks; } } public long Version { get { object obj; if (this._root.TryGetValue("~Version~", out obj)) { return (long)obj; } return 0L; } private set { this._root["~Version~"] = value; } } public Dictionary GetDictionary(string key) { if (string.IsNullOrEmpty(key)) { return new Dictionary(); } object obj; if (this.Root.TryGetValue(key, out obj) && obj is Dictionary) { return (Dictionary)obj; } Dictionary dictionary = new Dictionary(); this._root.Add(key, dictionary); return dictionary; } private void Load() { if (this._path == null) { this._root = new Dictionary(); } else { this._root = null; string[] array = this.ListSaveFiles(); int num = array.Length - 1; while (this._root == null && num >= 0) { string text = array[num]; UnityEngine.Debug.LogFormat("Loading file {0}", new object[] { text }); this._root = Storage.LoadDictionary(text); num--; if (this._root == null) { UnityEngine.Debug.LogWarningFormat("Failed to load file! Will try to load a backup!", new object[0]); } else { Storage._lastFileSaveDateTime[text] = this.UpdateTimestamp; } } if (this._root == null) { this._root = new Dictionary(); } } } private void Delete() { if (this._path != null) { string[] array = this.ListSaveFiles(); foreach (string text in array) { try { File.Delete(text); } catch (Exception ex) { UnityEngine.Debug.LogWarning("Unable to delete dictionary at " + text + ": " + ex.Message); } } } } private void DeleteOldVersions(int keepExtra) { int num = 14 + keepExtra; string[] array = this.ListSaveFiles(); for (int i = 0; i < array.Length - num; i++) { try { File.Delete(array[i]); } catch (Exception ex) { UnityEngine.Debug.LogWarning("Unable to delete dictionary at " + array[i] + ": " + ex.Message); } } } private string FindSaveFile(out bool isNew) { DateTime creationTimestamp = this.CreationTimestamp; DateTime utcNow = DateTime.UtcNow; long num = this.Version; if (Math.Abs(utcNow.Ticks - creationTimestamp.Ticks) >= 864000000000L) { num += 1L; this.Version = num; creationTimestamp = utcNow; this.CreationTimestamp = creationTimestamp; isNew = true; } else { isNew = false; } this.UpdateTimestamp = utcNow; return Path.Combine(this._path, "Data" + ((num != 0L) ? Convert.ToString(num, CultureInfo.InvariantCulture) : string.Empty)); } private string[] ListSaveFiles() { string[] array = null; string text = Path.Combine(Storage._storagePath, this._path); try { array = Directory.GetFiles(text, "Data*"); for (int i = 0; i < array.Length; i++) { array[i] = Path.Combine(text, array[i]); } } catch (DirectoryNotFoundException) { UnityEngine.Debug.Log("Unable to find files in " + text + " becuase the folder does not exist."); } catch (Exception ex) { UnityEngine.Debug.LogWarning("Unable to get files from " + text + ": " + ex.ToString()); } if (array == null) { array = new string[0]; } else { string[] array2 = new string[array.Length]; Array.Copy(array, array2, array.Length); array = array2; Exception parseException = null; string parseExceptionName = null; Array.Sort(array, delegate (string file1, string file2) { long num = 0L; string fileName = Path.GetFileName(file1); if (fileName.StartsWith("Data") && fileName.Length > "Data".Length) { try { num = Convert.ToInt64(fileName.Substring("Data".Length)); } catch (Exception ex2) { UnityEngine.Debug.LogWarning(string.Format("Unable to parse fileVersion of {0}: {1}", fileName, ex2)); parseException = ex2; parseExceptionName = fileName; } } long num2 = 0L; string fileName2 = Path.GetFileName(file2); if (fileName2.StartsWith("Data") && fileName2.Length > "Data".Length) { try { num2 = Convert.ToInt64(fileName2.Substring("Data".Length)); } catch (Exception ex3) { UnityEngine.Debug.LogWarning(string.Format("Unable to parse fileVersion of {0}: {1}", fileName, ex3)); parseException = ex3; parseExceptionName = fileName2; } } if (num < num2) { return -1; } if (num > num2) { return 1; } return 0; }); if (parseException != null) { string message = string.Format("Unable to parse fileVersion of {0}", parseExceptionName); UnityEngine.Debug.LogError(message); } } return array; } private static string _storagePath; private static Dictionary storableAliases; private static Dictionary _lastFileSaveDateTime; public const string RootFolder = "Storage"; public const string GameFolder = "Game"; public const string PurchasesFolder = "P"; public const string DataFilename = "Data"; private const int SerializationBufferLength = 20; private const int OldVersionCount = 14; private const long TimestampGranularity = 864000000000L; private const string CreationTimestampKey = "~Creation~"; private const string UpdateTimestampKey = "~Update~"; private const string VersionKey = "~Version~"; private static string currentPlayer = "Player"; private static List storageCache = new List(); private StorageLifecycle _lifecycle; private string _path; private Dictionary _root; [StructLayout(LayoutKind.Explicit)] private struct UIntToFloat { [FieldOffset(0)] public float FloatValue; [FieldOffset(0)] public uint UIntValue; } public delegate void OnSyncHandler(); private class CaughtException : Exception { public CaughtException(string message, Exception ex) : base(message, ex) { } } } }