Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 

1291 строка
47 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Globalization;
  5. using System.IO;
  6. using System.Reflection;
  7. using System.Runtime.InteropServices;
  8. using System.Text;
  9. using System.Text.RegularExpressions;
  10. using UnityEngine;
  11. namespace SUISS.Storage
  12. {
  13. public class Storage
  14. {
  15. static Storage()
  16. {
  17. Storage.storableAliases = new Dictionary<string, Type>();
  18. Storage._lastFileSaveDateTime = new Dictionary<string, DateTime>();
  19. foreach (Type type in Storage.GetAllTypes())
  20. {
  21. object[] customAttributes = type.GetCustomAttributes(typeof(StorableAlias), true);
  22. if (customAttributes != null)
  23. {
  24. foreach (StorableAlias storableAlias in customAttributes)
  25. {
  26. if (string.IsNullOrEmpty(storableAlias.FullName))
  27. {
  28. throw new Exception("Found a StorableAlias for " + type.FullName + " with a FullName that is null or an empty string.");
  29. }
  30. if (Storage.storableAliases.ContainsKey(storableAlias.FullName))
  31. {
  32. throw new Exception(string.Concat(new string[]
  33. {
  34. "Duplicate StorableAlias found: ",
  35. storableAlias.FullName,
  36. " is registered as alias for both ",
  37. Storage.storableAliases[storableAlias.FullName].FullName,
  38. " and ",
  39. type.FullName,
  40. "."
  41. }));
  42. }
  43. Storage.storableAliases[storableAlias.FullName] = type;
  44. }
  45. }
  46. }
  47. Storage._storagePath = Application.persistentDataPath;
  48. }
  49. private Storage(StorageLifecycle lifecycle)
  50. {
  51. this._lifecycle = lifecycle;
  52. this._path = null;
  53. if (this._lifecycle != StorageLifecycle.Session)
  54. {
  55. this._path = "Storage";
  56. if (this._lifecycle == StorageLifecycle.Purchases)
  57. {
  58. this._path = Path.Combine(this._path, "P");
  59. }
  60. else if (this._lifecycle != StorageLifecycle.Forever)
  61. {
  62. this._path = Path.Combine(this._path, WWW.EscapeURL(Storage.currentPlayer));
  63. if (this._lifecycle != StorageLifecycle.Player)
  64. {
  65. this._path = Path.Combine(this._path, "Game");
  66. }
  67. }
  68. }
  69. this.Load();
  70. }
  71. //[DebuggerBrowsable(DebuggerBrowsableState.Never)]
  72. public static event Action NewGameEvent;
  73. public static bool ShouldShowDiskFullWarning { get; private set; }
  74. public static string CurrentPlayer
  75. {
  76. get
  77. {
  78. return Storage.currentPlayer;
  79. }
  80. }
  81. private static Type[] GetAllTypes()
  82. {
  83. return Assembly.GetExecutingAssembly().GetTypes();
  84. }
  85. public static Storage Get(StorageLifecycle lifecycle)
  86. {
  87. if (lifecycle < StorageLifecycle.Forever)
  88. {
  89. return null;
  90. }
  91. while (lifecycle >= (StorageLifecycle)Storage.storageCache.Count)
  92. {
  93. Storage.storageCache.Add(null);
  94. }
  95. if (Storage.storageCache[(int)lifecycle] == null)
  96. {
  97. Storage.storageCache[(int)lifecycle] = new Storage(lifecycle);
  98. }
  99. return Storage.storageCache[(int)lifecycle];
  100. }
  101. public static void ChangePlayer(string player, bool deleteOld)
  102. {
  103. if (player == null)
  104. {
  105. throw new ArgumentException("Player can't be null.", "player");
  106. }
  107. if (deleteOld)
  108. {
  109. Storage storage = Storage.Get(StorageLifecycle.Player);
  110. storage.Delete();
  111. }
  112. Storage.storageCache[1] = null;
  113. Storage.currentPlayer = player;
  114. }
  115. public static void NewGame()
  116. {
  117. Storage storage = Storage.Get(StorageLifecycle.Game);
  118. storage.Delete();
  119. Storage.storageCache[2] = null;
  120. if (Storage.NewGameEvent != null)
  121. {
  122. Storage.NewGameEvent();
  123. }
  124. }
  125. public static void NewSession()
  126. {
  127. Storage storage = Storage.Get(StorageLifecycle.Session);
  128. storage.Delete();
  129. Storage.storageCache[3] = null;
  130. }
  131. public static void SaveAll(bool obsolete = false)
  132. {
  133. Storage.Save(Storage.storageCache);
  134. }
  135. public static void Save(IEnumerable<Storage> storages)
  136. {
  137. Dictionary<string, Dictionary<string, object>> dictionary = new Dictionary<string, Dictionary<string, object>>();
  138. foreach (Storage storage in storages)
  139. {
  140. if (storage != null && storage._path != null)
  141. {
  142. bool flag;
  143. string key = storage.FindSaveFile(out flag);
  144. dictionary[key] = storage.Root;
  145. storage.DeleteOldVersions((!flag) ? 0 : -1);
  146. }
  147. }
  148. foreach (string text in dictionary.Keys)
  149. {
  150. Dictionary<string, object> dictionary2 = dictionary[text];
  151. Exception arg = null;
  152. string text2 = Path.Combine(Storage._storagePath, text);
  153. if (!Storage.SaveDictionary(dictionary2, text2, out arg))
  154. {
  155. string message = string.Format("Unable to save dictionary to {0}: {1}", text, arg);
  156. UnityEngine.Debug.LogError(message);
  157. DateTime dateTime;
  158. string text3 = (!Storage._lastFileSaveDateTime.TryGetValue(text2, out dateTime)) ? "Never" : dateTime.ToString("yyyy-MM-dd HH:mm:ss.fff");
  159. UnityEngine.Debug.LogErrorFormat("[Unable to save {0}] Previous save time: {1} ; Current time: {2}", new object[]
  160. {
  161. text,
  162. text3,
  163. DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff")
  164. });
  165. }
  166. else
  167. {
  168. Storage._lastFileSaveDateTime[text2] = DateTime.UtcNow;
  169. }
  170. }
  171. }
  172. public static void SaveLifecycle(StorageLifecycle lifecycle, bool obsolete = false)
  173. {
  174. Storage.Save(new List<Storage>
  175. {
  176. Storage.Get(lifecycle)
  177. });
  178. }
  179. public static Dictionary<string, object> LoadDictionary(string filename)
  180. {
  181. Dictionary<string, object> result = null;
  182. if (filename != null && File.Exists(filename))
  183. {
  184. try
  185. {
  186. using (Stream stream = File.Open(filename, FileMode.Open, FileAccess.Read))
  187. {
  188. result = (Dictionary<string, object>)Storage.DeserializeObject(stream, new byte[20], new List<string>());
  189. }
  190. }
  191. catch (Exception ex)
  192. {
  193. UnityEngine.Debug.LogErrorFormat("Unable to load dictionary to {0}: {1}", new object[]
  194. {
  195. filename,
  196. ex.ToString()
  197. });
  198. }
  199. }
  200. return result;
  201. }
  202. public static bool ExceptionMeansFullDisk(Exception ex)
  203. {
  204. return ex != null && !string.IsNullOrEmpty(ex.Message) && ex.Message.ToLower().Contains("disk full");
  205. }
  206. public static bool SaveDictionary(Dictionary<string, object> dictionary, string filename, out Exception outException)
  207. {
  208. outException = null;
  209. if (filename == null || dictionary == null)
  210. {
  211. return false;
  212. }
  213. try
  214. {
  215. string directoryName = Path.GetDirectoryName(filename);
  216. if (directoryName != null && !Directory.Exists(directoryName))
  217. {
  218. Directory.CreateDirectory(directoryName);
  219. }
  220. }
  221. catch (Exception innerException)
  222. {
  223. outException = new Exception("Directory creation failed.", innerException);
  224. return false;
  225. }
  226. string text = Path.Combine(Path.GetDirectoryName(filename), "tmp_" + Path.GetFileName(filename));
  227. Stream stream = null;
  228. try
  229. {
  230. stream = File.Open(text, FileMode.Create, FileAccess.Write);
  231. Storage.SerializeObject(stream, dictionary, new byte[20], new Dictionary<string, uint>());
  232. }
  233. catch (Exception ex)
  234. {
  235. if (Storage.ExceptionMeansFullDisk(ex) || Storage.ExceptionMeansFullDisk(ex.InnerException))
  236. {
  237. Storage.ShowDiskFullWarning();
  238. }
  239. outException = new Exception("Stream opening & writing failed.", ex);
  240. return false;
  241. }
  242. finally
  243. {
  244. try
  245. {
  246. stream.Dispose();
  247. }
  248. catch (Exception)
  249. {
  250. }
  251. }
  252. if (File.Exists(filename))
  253. {
  254. try
  255. {
  256. File.Delete(filename);
  257. }
  258. catch (Exception innerException2)
  259. {
  260. outException = new Exception("Existing save file removal failed.", innerException2);
  261. return false;
  262. }
  263. }
  264. try
  265. {
  266. File.Move(text, filename);
  267. }
  268. catch (Exception innerException3)
  269. {
  270. outException = new Exception("Temporary file renaming failed.", innerException3);
  271. return false;
  272. }
  273. return true;
  274. }
  275. public static Dictionary<string, object> CloneDictionary(Dictionary<string, object> dictionary)
  276. {
  277. if (dictionary == null)
  278. {
  279. return null;
  280. }
  281. Dictionary<string, object> dictionary2 = new Dictionary<string, object>(dictionary.Count);
  282. foreach (KeyValuePair<string, object> keyValuePair in dictionary)
  283. {
  284. dictionary2[keyValuePair.Key] = Storage.CloneObject(keyValuePair.Value);
  285. }
  286. return dictionary2;
  287. }
  288. public static List<object> CloneList(List<object> list)
  289. {
  290. if (list == null)
  291. {
  292. return null;
  293. }
  294. List<object> list2 = new List<object>(list.Count);
  295. foreach (object o in list)
  296. {
  297. list2.Add(Storage.CloneObject(o));
  298. }
  299. return list2;
  300. }
  301. public static object[] CloneArray(object[] array)
  302. {
  303. if (array == null)
  304. {
  305. return null;
  306. }
  307. object[] array2 = new object[array.Length];
  308. for (int i = 0; i < array.Length; i++)
  309. {
  310. array2[i] = Storage.CloneObject(array[i]);
  311. }
  312. return array2;
  313. }
  314. public static IStorable CloneIStorable(IStorable storable)
  315. {
  316. if (storable == null)
  317. {
  318. return null;
  319. }
  320. IDictionary<string, object> dict = storable.ToStorage();
  321. Type type = storable.GetType();
  322. ConstructorInfo constructor = type.GetConstructor(new Type[0]);
  323. if (constructor == null)
  324. {
  325. throw new FormatException("Type " + type.AssemblyQualifiedName + " does not have an empty constructor.");
  326. }
  327. IStorable storable2 = (IStorable)constructor.Invoke(null);
  328. storable2.FromStorage(dict);
  329. return storable2;
  330. }
  331. public static object CloneObject(object o)
  332. {
  333. if (o is Dictionary<string, object>)
  334. {
  335. return Storage.CloneDictionary((Dictionary<string, object>)o);
  336. }
  337. if (o is List<object>)
  338. {
  339. return Storage.CloneList((List<object>)o);
  340. }
  341. if (o is object[])
  342. {
  343. return Storage.CloneArray((object[])o);
  344. }
  345. if (o is ICloneable)
  346. {
  347. return ((ICloneable)o).Clone();
  348. }
  349. if (o is IStorable)
  350. {
  351. return Storage.CloneIStorable((IStorable)o);
  352. }
  353. if (o != null && !o.GetType().IsValueType)
  354. {
  355. UnityEngine.Debug.LogErrorFormat("\"Cloning\" type {0}", new object[]
  356. {
  357. o.GetType()
  358. });
  359. }
  360. return o;
  361. }
  362. public static bool VerifyType(object o)
  363. {
  364. return Storage.VerifyType(o, false);
  365. }
  366. public static bool VerifyType(object o, bool throwException)
  367. {
  368. if (object.ReferenceEquals(o, null) || o is Dictionary<string, object> || o is List<object> || 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)
  369. {
  370. return true;
  371. }
  372. if (throwException)
  373. {
  374. throw new ArgumentException(string.Concat(new object[]
  375. {
  376. "Value ",
  377. o,
  378. " of type ",
  379. o.GetType().AssemblyQualifiedName,
  380. " is not a storable type."
  381. }));
  382. }
  383. return false;
  384. }
  385. public static string DictToString(Dictionary<string, object> storage)
  386. {
  387. string result;
  388. using (Stream stream = new MemoryStream())
  389. {
  390. Storage.SerializeObject(stream, storage, new byte[20], new Dictionary<string, uint>());
  391. stream.Flush();
  392. stream.Position = 0L;
  393. string text = Convert.ToBase64String(Storage.ReadFully(stream));
  394. result = text;
  395. }
  396. return result;
  397. }
  398. public static Dictionary<string, object> StringToDict(string input)
  399. {
  400. byte[] buffer = Convert.FromBase64String(input);
  401. Dictionary<string, object> result;
  402. using (MemoryStream memoryStream = new MemoryStream(buffer))
  403. {
  404. memoryStream.Flush();
  405. memoryStream.Position = 0L;
  406. result = (Dictionary<string, object>)Storage.DeserializeObject(memoryStream, new byte[20], new List<string>());
  407. }
  408. return result;
  409. }
  410. public static bool UnityVersionIsAtLeast(string version, int major, int minor, int revision, int patch)
  411. {
  412. Regex regex = new Regex("^([0-9]+)\\.([0-9]+)\\.([0-9]+)(?:(.)([0-9]+))?$", RegexOptions.CultureInvariant);
  413. Match match = regex.Match(version);
  414. if (!match.Success)
  415. {
  416. return true;
  417. }
  418. int num = int.Parse(match.Groups[1].ToString());
  419. int num2 = int.Parse(match.Groups[2].ToString());
  420. int num3 = int.Parse(match.Groups[3].ToString());
  421. int num4 = (!match.Groups[5].Success) ? 0 : int.Parse(match.Groups[5].ToString());
  422. if (num != major)
  423. {
  424. return num > major;
  425. }
  426. if (num2 != minor)
  427. {
  428. return num2 > minor;
  429. }
  430. if (num3 != revision)
  431. {
  432. return num3 > revision;
  433. }
  434. return num4 >= patch;
  435. }
  436. private static object DeserializeObject(Stream stream, byte[] buffer, List<string> stringTable)
  437. {
  438. int num = stream.ReadByte();
  439. if (num < 0)
  440. {
  441. throw new FormatException("Unexpected end of stream.");
  442. }
  443. char c = (char)num;
  444. if (c == 'n')
  445. {
  446. return null;
  447. }
  448. if (c == '{')
  449. {
  450. int num2 = (int)Storage.ReadLength(stream);
  451. Dictionary<string, object> dictionary = new Dictionary<string, object>(num2);
  452. for (int i = 0; i < num2; i++)
  453. {
  454. string key = (string)Storage.DeserializeObject(stream, buffer, stringTable);
  455. object value = Storage.DeserializeObject(stream, buffer, stringTable);
  456. dictionary.Add(key, value);
  457. }
  458. return dictionary;
  459. }
  460. if (c == '[')
  461. {
  462. int num3 = (int)Storage.ReadLength(stream);
  463. List<object> list = new List<object>();
  464. for (int j = 0; j < num3; j++)
  465. {
  466. object item = Storage.DeserializeObject(stream, buffer, stringTable);
  467. list.Add(item);
  468. }
  469. return list;
  470. }
  471. if (c == ']')
  472. {
  473. int num4 = (int)Storage.ReadLength(stream);
  474. object[] array = new object[num4];
  475. for (int k = 0; k < num4; k++)
  476. {
  477. array[k] = Storage.DeserializeObject(stream, buffer, stringTable);
  478. }
  479. return array;
  480. }
  481. if (c == '$')
  482. {
  483. int num5 = (int)Storage.ReadLength(stream);
  484. byte[] array2 = new byte[num5];
  485. if (stream.Read(array2, 0, num5) != num5)
  486. {
  487. throw new FormatException("Unexpected end of stream.");
  488. }
  489. string @string = Encoding.UTF8.GetString(array2, 0, array2.Length);
  490. stringTable.Add(@string);
  491. return @string;
  492. }
  493. else if (c == '#')
  494. {
  495. int num6 = (int)Storage.ReadLength(stream);
  496. if (num6 < 0 || num6 >= stringTable.Count)
  497. {
  498. throw new FormatException("String table index out of bounds.");
  499. }
  500. return stringTable[num6];
  501. }
  502. else if (c == '@')
  503. {
  504. string text = (string)Storage.DeserializeObject(stream, buffer, stringTable);
  505. Dictionary<string, object> dictionary2 = (Dictionary<string, object>)Storage.DeserializeObject(stream, buffer, stringTable);
  506. string typeFullName = Storage.GetTypeFullName(text);
  507. Type type;
  508. if (Storage.storableAliases.ContainsKey(typeFullName))
  509. {
  510. type = Storage.storableAliases[typeFullName];
  511. }
  512. else
  513. {
  514. type = Type.GetType(text);
  515. if (type == null)
  516. {
  517. UnityEngine.Debug.LogError(string.Format("Unable to find type {0} while deserializing. Will return Dictionary<string, object> instead.", text));
  518. return dictionary2;
  519. }
  520. }
  521. ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes);
  522. object obj;
  523. if (constructor == null)
  524. {
  525. obj = Activator.CreateInstance(type);
  526. }
  527. else
  528. {
  529. obj = constructor.Invoke(null);
  530. }
  531. if (obj == null)
  532. {
  533. throw new FormatException("Type " + text + " does not have an empty constructor; nor is it a struct with default constructor.");
  534. }
  535. ((IStorable)obj).FromStorage(dictionary2);
  536. return obj;
  537. }
  538. else
  539. {
  540. if (c == '1')
  541. {
  542. return true;
  543. }
  544. if (c == '0')
  545. {
  546. return false;
  547. }
  548. if (c == 'c')
  549. {
  550. if (stream.Read(buffer, 0, 2) != 2)
  551. {
  552. throw new FormatException("Unexpected end of stream.");
  553. }
  554. return (char)((int)buffer[0] << 8 | (int)buffer[1]);
  555. }
  556. else
  557. {
  558. if (c == 'f')
  559. {
  560. Storage.UIntToFloat uintToFloat = default(Storage.UIntToFloat);
  561. uintToFloat.UIntValue = Storage.ReadInt(stream, buffer);
  562. return uintToFloat.FloatValue;
  563. }
  564. if (c == 'd')
  565. {
  566. uint num7 = Storage.ReadInt(stream, buffer);
  567. uint num8 = Storage.ReadInt(stream, buffer);
  568. return BitConverter.Int64BitsToDouble((long)((ulong)num7 << 32 | (ulong)num8));
  569. }
  570. if (c == 'b')
  571. {
  572. int num9 = stream.ReadByte();
  573. if (num9 < 0)
  574. {
  575. throw new FormatException("Unexpected end of stream.");
  576. }
  577. return (sbyte)num9;
  578. }
  579. else if (c == 'B')
  580. {
  581. int num10 = stream.ReadByte();
  582. if (num10 < 0)
  583. {
  584. throw new FormatException("Unexpected end of stream.");
  585. }
  586. return (byte)num10;
  587. }
  588. else if (c == 's')
  589. {
  590. if (stream.Read(buffer, 0, 2) != 2)
  591. {
  592. throw new FormatException("Unexpected end of stream.");
  593. }
  594. return (short)((int)buffer[0] << 8 | (int)buffer[1]);
  595. }
  596. else if (c == 'S')
  597. {
  598. if (stream.Read(buffer, 0, 2) != 2)
  599. {
  600. throw new FormatException("Unexpected end of stream.");
  601. }
  602. return (ushort)((int)buffer[0] << 8 | (int)buffer[1]);
  603. }
  604. else
  605. {
  606. if (c == 'i')
  607. {
  608. return (int)Storage.ReadInt(stream, buffer);
  609. }
  610. if (c == 'I')
  611. {
  612. return Storage.ReadInt(stream, buffer);
  613. }
  614. if (c == 'l')
  615. {
  616. if (stream.Read(buffer, 0, 8) != 8)
  617. {
  618. throw new FormatException("Unexpected end of stream.");
  619. }
  620. 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]);
  621. }
  622. else if (c == 'L')
  623. {
  624. if (stream.Read(buffer, 0, 8) != 8)
  625. {
  626. throw new FormatException("Unexpected end of stream.");
  627. }
  628. 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];
  629. }
  630. else
  631. {
  632. if (c == 'a')
  633. {
  634. int[] array3 = new int[4];
  635. for (int l = 0; l < 4; l++)
  636. {
  637. array3[l] = (int)Storage.ReadInt(stream, buffer);
  638. }
  639. return new decimal(array3);
  640. }
  641. throw new FormatException("Unknown type (" + c + ") encountered.");
  642. }
  643. }
  644. }
  645. }
  646. }
  647. private static void SerializeObject(Stream stream, object o, byte[] buffer, Dictionary<string, uint> stringTable)
  648. {
  649. try
  650. {
  651. if (object.ReferenceEquals(o, null))
  652. {
  653. stream.WriteByte(110);
  654. }
  655. else if (o is Dictionary<string, object>)
  656. {
  657. Dictionary<string, object> dictionary = (Dictionary<string, object>)o;
  658. stream.WriteByte(123);
  659. WriteLength(stream, (uint)dictionary.Count, buffer);
  660. foreach (KeyValuePair<string, object> item in dictionary)
  661. {
  662. SerializeObject(stream, item.Key, buffer, stringTable);
  663. SerializeObject(stream, item.Value, buffer, stringTable);
  664. }
  665. }
  666. else if (o is List<object>)
  667. {
  668. List<object> list = (List<object>)o;
  669. stream.WriteByte(91);
  670. WriteLength(stream, (uint)list.Count, buffer);
  671. foreach (object item2 in list)
  672. {
  673. SerializeObject(stream, item2, buffer, stringTable);
  674. }
  675. }
  676. else if (o is object[])
  677. {
  678. object[] array = (object[])o;
  679. stream.WriteByte(93);
  680. WriteLength(stream, (uint)array.Length, buffer);
  681. object[] array2 = array;
  682. foreach (object o2 in array2)
  683. {
  684. SerializeObject(stream, o2, buffer, stringTable);
  685. }
  686. }
  687. else if (o is string)
  688. {
  689. string text = (string)o; uint value;
  690. if (stringTable.TryGetValue(text, out value))
  691. {
  692. stream.WriteByte(35);
  693. WriteLength(stream, value, buffer);
  694. }
  695. else
  696. {
  697. byte[] bytes = Encoding.UTF8.GetBytes(text);
  698. stream.WriteByte(36);
  699. WriteLength(stream, (uint)bytes.Length, buffer);
  700. stream.Write(bytes, 0, bytes.Length);
  701. stringTable[text] = (uint)stringTable.Count;
  702. }
  703. }
  704. else if (o is bool)
  705. {
  706. if ((bool)o)
  707. {
  708. stream.WriteByte(49);
  709. }
  710. else
  711. {
  712. stream.WriteByte(48);
  713. }
  714. }
  715. else if (o is char)
  716. {
  717. int num = (char)o;
  718. buffer[0] = 99;
  719. buffer[1] = (byte)(num >> 8);
  720. buffer[2] = (byte)(num & 0xFF);
  721. stream.Write(buffer, 0, 3);
  722. }
  723. else if (o is float)
  724. {
  725. UIntToFloat uIntToFloat = default(UIntToFloat);
  726. uIntToFloat.FloatValue = (float)o;
  727. stream.WriteByte(102);
  728. WriteInt(stream, uIntToFloat.UIntValue, buffer);
  729. }
  730. else if (o is double)
  731. {
  732. ulong num2 = (ulong)BitConverter.DoubleToInt64Bits((double)o);
  733. stream.WriteByte(100);
  734. WriteInt(stream, (uint)(num2 >> 32), buffer);
  735. WriteInt(stream, (uint)(num2 & uint.MaxValue), buffer);
  736. }
  737. else if (o is sbyte)
  738. {
  739. byte b = (byte)(sbyte)o;
  740. buffer[0] = 98;
  741. buffer[1] = b;
  742. stream.Write(buffer, 0, 2);
  743. }
  744. else if (o is byte)
  745. {
  746. byte b2 = (byte)o;
  747. buffer[0] = 66;
  748. buffer[1] = b2;
  749. stream.Write(buffer, 0, 2);
  750. }
  751. else if (o is short)
  752. {
  753. uint num3 = (uint)(short)o;
  754. buffer[0] = 115;
  755. buffer[1] = (byte)(num3 >> 8);
  756. buffer[2] = (byte)(num3 & 0xFF);
  757. stream.Write(buffer, 0, 3);
  758. }
  759. else if (o is ushort)
  760. {
  761. uint num4 = (ushort)o;
  762. buffer[0] = 83;
  763. buffer[1] = (byte)(num4 >> 8);
  764. buffer[2] = (byte)(num4 & 0xFF);
  765. stream.Write(buffer, 0, 3);
  766. }
  767. else if (o is int)
  768. {
  769. uint num5 = (uint)(int)o;
  770. buffer[0] = 105;
  771. buffer[1] = (byte)(num5 >> 24);
  772. buffer[2] = (byte)((num5 >> 16) & 0xFF);
  773. buffer[3] = (byte)((num5 >> 8) & 0xFF);
  774. buffer[4] = (byte)(num5 & 0xFF);
  775. stream.Write(buffer, 0, 5);
  776. }
  777. else if (o is uint)
  778. {
  779. uint num6 = (uint)o;
  780. buffer[0] = 73;
  781. buffer[1] = (byte)(num6 >> 24);
  782. buffer[2] = (byte)((num6 >> 16) & 0xFF);
  783. buffer[3] = (byte)((num6 >> 8) & 0xFF);
  784. buffer[4] = (byte)(num6 & 0xFF);
  785. stream.Write(buffer, 0, 5);
  786. }
  787. else if (o is long)
  788. {
  789. ulong num7 = (ulong)(long)o;
  790. buffer[0] = 108;
  791. buffer[1] = (byte)(num7 >> 56);
  792. buffer[2] = (byte)((num7 >> 48) & 0xFF);
  793. buffer[3] = (byte)((num7 >> 40) & 0xFF);
  794. buffer[4] = (byte)((num7 >> 32) & 0xFF);
  795. buffer[5] = (byte)((num7 >> 24) & 0xFF);
  796. buffer[6] = (byte)((num7 >> 16) & 0xFF);
  797. buffer[7] = (byte)((num7 >> 8) & 0xFF);
  798. buffer[8] = (byte)(num7 & 0xFF);
  799. stream.Write(buffer, 0, 9);
  800. }
  801. else if (o is ulong)
  802. {
  803. ulong num8 = (ulong)o;
  804. buffer[0] = 76;
  805. buffer[1] = (byte)(num8 >> 56);
  806. buffer[2] = (byte)((num8 >> 48) & 0xFF);
  807. buffer[3] = (byte)((num8 >> 40) & 0xFF);
  808. buffer[4] = (byte)((num8 >> 32) & 0xFF);
  809. buffer[5] = (byte)((num8 >> 24) & 0xFF);
  810. buffer[6] = (byte)((num8 >> 16) & 0xFF);
  811. buffer[7] = (byte)((num8 >> 8) & 0xFF);
  812. buffer[8] = (byte)(num8 & 0xFF);
  813. stream.Write(buffer, 0, 9);
  814. }
  815. else if (o is decimal)
  816. {
  817. decimal d = (decimal)o;
  818. stream.WriteByte(97);
  819. int[] bits = decimal.GetBits(d);
  820. for (int j = 0; j < 4; j++)
  821. {
  822. WriteInt(stream, (uint)bits[j], buffer);
  823. }
  824. }
  825. else
  826. {
  827. if (!(o is IStorable))
  828. {
  829. throw new FormatException("Can't serialize object " + o.ToString() + " because it does not implement IStorable.");
  830. }
  831. stream.WriteByte(64);
  832. SerializeObject(stream, o.GetType().AssemblyQualifiedName, buffer, stringTable);
  833. SerializeObject(stream, ((IStorable)o).ToStorage(), buffer, stringTable);
  834. }
  835. }
  836. catch (CaughtException)
  837. {
  838. throw;
  839. }
  840. catch (Exception ex2)
  841. {
  842. string message = string.Format("SerializeObject exception of object of type {0}", (o != null) ? o.GetType().ToString() : "null");
  843. throw new CaughtException(message, ex2);
  844. }
  845. }
  846. private static void WriteLength(Stream stream, uint length, byte[] buffer)
  847. {
  848. int count = 0;
  849. uint num;
  850. for (num = length; num >= 128u; num >>= 7)
  851. {
  852. buffer[count++] = (byte)(128u | (num & 127u));
  853. }
  854. buffer[count++] = (byte)num;
  855. stream.Write(buffer, 0, count);
  856. }
  857. private static uint ReadLength(Stream stream)
  858. {
  859. uint num = 0u;
  860. int num2 = 0;
  861. int num3;
  862. while ((num3 = stream.ReadByte()) >= 128)
  863. {
  864. if (num2 >= 4)
  865. {
  866. throw new FormatException("Invalid length.");
  867. }
  868. num |= (uint)((uint)(num3 & 127) << num2 * 7);
  869. num2++;
  870. }
  871. if (num3 < 0)
  872. {
  873. throw new FormatException("Unexpected end of stream.");
  874. }
  875. return num | (uint)((uint)num3 << num2 * 7);
  876. }
  877. private static void WriteInt(Stream stream, uint i, byte[] buffer)
  878. {
  879. buffer[0] = (byte)(i >> 24);
  880. buffer[1] = (byte)(i >> 16 & 255u);
  881. buffer[2] = (byte)(i >> 8 & 255u);
  882. buffer[3] = (byte)(i & 255u);
  883. stream.Write(buffer, 0, 4);
  884. }
  885. private static uint ReadInt(Stream stream, byte[] buffer)
  886. {
  887. int num = stream.Read(buffer, 0, 4);
  888. if (num != 4)
  889. {
  890. throw new FormatException("Unexpected end of stream.");
  891. }
  892. return (uint)((int)buffer[0] << 24 | (int)buffer[1] << 16 | (int)buffer[2] << 8 | (int)buffer[3]);
  893. }
  894. private static void ShowDiskFullWarning()
  895. {
  896. Storage.ShouldShowDiskFullWarning = true;
  897. }
  898. private static string GetTypeFullName(string assemblyQualifiedName)
  899. {
  900. int num = assemblyQualifiedName.IndexOf(',');
  901. if (num >= 0)
  902. {
  903. return assemblyQualifiedName.Substring(0, num);
  904. }
  905. return assemblyQualifiedName;
  906. }
  907. private static byte[] ReadFully(Stream stream)
  908. {
  909. byte[] array = new byte[32768];
  910. byte[] result;
  911. using (MemoryStream memoryStream = new MemoryStream())
  912. {
  913. for (; ; )
  914. {
  915. int num = stream.Read(array, 0, array.Length);
  916. if (num <= 0)
  917. {
  918. break;
  919. }
  920. memoryStream.Write(array, 0, num);
  921. }
  922. result = memoryStream.ToArray();
  923. }
  924. return result;
  925. }
  926. //[DebuggerBrowsable(DebuggerBrowsableState.Never)]
  927. public event Storage.OnSyncHandler OnSync;
  928. public StorageLifecycle Lifecycle
  929. {
  930. get
  931. {
  932. return this._lifecycle;
  933. }
  934. }
  935. public Dictionary<string, object> Root
  936. {
  937. get
  938. {
  939. if (this.OnSync != null)
  940. {
  941. this.OnSync();
  942. }
  943. return this._root;
  944. }
  945. }
  946. public DateTime CreationTimestamp
  947. {
  948. get
  949. {
  950. object obj;
  951. if (this._root.TryGetValue("~Creation~", out obj))
  952. {
  953. return new DateTime((long)obj, DateTimeKind.Utc);
  954. }
  955. return DateTime.MinValue;
  956. }
  957. private set
  958. {
  959. if (value.Kind != DateTimeKind.Utc)
  960. {
  961. value = value.ToUniversalTime();
  962. }
  963. this._root["~Creation~"] = value.Ticks;
  964. }
  965. }
  966. public DateTime UpdateTimestamp
  967. {
  968. get
  969. {
  970. object obj;
  971. if (this._root.TryGetValue("~Update~", out obj))
  972. {
  973. return new DateTime((long)obj, DateTimeKind.Utc);
  974. }
  975. return DateTime.MinValue;
  976. }
  977. private set
  978. {
  979. if (value.Kind != DateTimeKind.Utc)
  980. {
  981. value = value.ToUniversalTime();
  982. }
  983. this._root["~Update~"] = value.Ticks;
  984. }
  985. }
  986. public long Version
  987. {
  988. get
  989. {
  990. object obj;
  991. if (this._root.TryGetValue("~Version~", out obj))
  992. {
  993. return (long)obj;
  994. }
  995. return 0L;
  996. }
  997. private set
  998. {
  999. this._root["~Version~"] = value;
  1000. }
  1001. }
  1002. public Dictionary<string, object> GetDictionary(string key)
  1003. {
  1004. if (string.IsNullOrEmpty(key))
  1005. {
  1006. return new Dictionary<string, object>();
  1007. }
  1008. object obj;
  1009. if (this.Root.TryGetValue(key, out obj) && obj is Dictionary<string, object>)
  1010. {
  1011. return (Dictionary<string, object>)obj;
  1012. }
  1013. Dictionary<string, object> dictionary = new Dictionary<string, object>();
  1014. this._root.Add(key, dictionary);
  1015. return dictionary;
  1016. }
  1017. private void Load()
  1018. {
  1019. if (this._path == null)
  1020. {
  1021. this._root = new Dictionary<string, object>();
  1022. }
  1023. else
  1024. {
  1025. this._root = null;
  1026. string[] array = this.ListSaveFiles();
  1027. int num = array.Length - 1;
  1028. while (this._root == null && num >= 0)
  1029. {
  1030. string text = array[num];
  1031. UnityEngine.Debug.LogFormat("Loading file {0}", new object[]
  1032. {
  1033. text
  1034. });
  1035. this._root = Storage.LoadDictionary(text);
  1036. num--;
  1037. if (this._root == null)
  1038. {
  1039. UnityEngine.Debug.LogWarningFormat("Failed to load file! Will try to load a backup!", new object[0]);
  1040. }
  1041. else
  1042. {
  1043. Storage._lastFileSaveDateTime[text] = this.UpdateTimestamp;
  1044. }
  1045. }
  1046. if (this._root == null)
  1047. {
  1048. this._root = new Dictionary<string, object>();
  1049. }
  1050. }
  1051. }
  1052. private void Delete()
  1053. {
  1054. if (this._path != null)
  1055. {
  1056. string[] array = this.ListSaveFiles();
  1057. foreach (string text in array)
  1058. {
  1059. try
  1060. {
  1061. File.Delete(text);
  1062. }
  1063. catch (Exception ex)
  1064. {
  1065. UnityEngine.Debug.LogWarning("Unable to delete dictionary at " + text + ": " + ex.Message);
  1066. }
  1067. }
  1068. }
  1069. }
  1070. private void DeleteOldVersions(int keepExtra)
  1071. {
  1072. int num = 14 + keepExtra;
  1073. string[] array = this.ListSaveFiles();
  1074. for (int i = 0; i < array.Length - num; i++)
  1075. {
  1076. try
  1077. {
  1078. File.Delete(array[i]);
  1079. }
  1080. catch (Exception ex)
  1081. {
  1082. UnityEngine.Debug.LogWarning("Unable to delete dictionary at " + array[i] + ": " + ex.Message);
  1083. }
  1084. }
  1085. }
  1086. private string FindSaveFile(out bool isNew)
  1087. {
  1088. DateTime creationTimestamp = this.CreationTimestamp;
  1089. DateTime utcNow = DateTime.UtcNow;
  1090. long num = this.Version;
  1091. if (Math.Abs(utcNow.Ticks - creationTimestamp.Ticks) >= 864000000000L)
  1092. {
  1093. num += 1L;
  1094. this.Version = num;
  1095. creationTimestamp = utcNow;
  1096. this.CreationTimestamp = creationTimestamp;
  1097. isNew = true;
  1098. }
  1099. else
  1100. {
  1101. isNew = false;
  1102. }
  1103. this.UpdateTimestamp = utcNow;
  1104. return Path.Combine(this._path, "Data" + ((num != 0L) ? Convert.ToString(num, CultureInfo.InvariantCulture) : string.Empty));
  1105. }
  1106. private string[] ListSaveFiles()
  1107. {
  1108. string[] array = null;
  1109. string text = Path.Combine(Storage._storagePath, this._path);
  1110. try
  1111. {
  1112. array = Directory.GetFiles(text, "Data*");
  1113. for (int i = 0; i < array.Length; i++)
  1114. {
  1115. array[i] = Path.Combine(text, array[i]);
  1116. }
  1117. }
  1118. catch (DirectoryNotFoundException)
  1119. {
  1120. UnityEngine.Debug.Log("Unable to find files in " + text + " becuase the folder does not exist.");
  1121. }
  1122. catch (Exception ex)
  1123. {
  1124. UnityEngine.Debug.LogWarning("Unable to get files from " + text + ": " + ex.ToString());
  1125. }
  1126. if (array == null)
  1127. {
  1128. array = new string[0];
  1129. }
  1130. else
  1131. {
  1132. string[] array2 = new string[array.Length];
  1133. Array.Copy(array, array2, array.Length);
  1134. array = array2;
  1135. Exception parseException = null;
  1136. string parseExceptionName = null;
  1137. Array.Sort<string>(array, delegate (string file1, string file2)
  1138. {
  1139. long num = 0L;
  1140. string fileName = Path.GetFileName(file1);
  1141. if (fileName.StartsWith("Data") && fileName.Length > "Data".Length)
  1142. {
  1143. try
  1144. {
  1145. num = Convert.ToInt64(fileName.Substring("Data".Length));
  1146. }
  1147. catch (Exception ex2)
  1148. {
  1149. UnityEngine.Debug.LogWarning(string.Format("Unable to parse fileVersion of {0}: {1}", fileName, ex2));
  1150. parseException = ex2;
  1151. parseExceptionName = fileName;
  1152. }
  1153. }
  1154. long num2 = 0L;
  1155. string fileName2 = Path.GetFileName(file2);
  1156. if (fileName2.StartsWith("Data") && fileName2.Length > "Data".Length)
  1157. {
  1158. try
  1159. {
  1160. num2 = Convert.ToInt64(fileName2.Substring("Data".Length));
  1161. }
  1162. catch (Exception ex3)
  1163. {
  1164. UnityEngine.Debug.LogWarning(string.Format("Unable to parse fileVersion of {0}: {1}", fileName, ex3));
  1165. parseException = ex3;
  1166. parseExceptionName = fileName2;
  1167. }
  1168. }
  1169. if (num < num2)
  1170. {
  1171. return -1;
  1172. }
  1173. if (num > num2)
  1174. {
  1175. return 1;
  1176. }
  1177. return 0;
  1178. });
  1179. if (parseException != null)
  1180. {
  1181. string message = string.Format("Unable to parse fileVersion of {0}", parseExceptionName);
  1182. UnityEngine.Debug.LogError(message);
  1183. }
  1184. }
  1185. return array;
  1186. }
  1187. private static string _storagePath;
  1188. private static Dictionary<string, Type> storableAliases;
  1189. private static Dictionary<string, DateTime> _lastFileSaveDateTime;
  1190. public const string RootFolder = "Storage";
  1191. public const string GameFolder = "Game";
  1192. public const string PurchasesFolder = "P";
  1193. public const string DataFilename = "Data";
  1194. private const int SerializationBufferLength = 20;
  1195. private const int OldVersionCount = 14;
  1196. private const long TimestampGranularity = 864000000000L;
  1197. private const string CreationTimestampKey = "~Creation~";
  1198. private const string UpdateTimestampKey = "~Update~";
  1199. private const string VersionKey = "~Version~";
  1200. private static string currentPlayer = "Player";
  1201. private static List<Storage> storageCache = new List<Storage>();
  1202. private StorageLifecycle _lifecycle;
  1203. private string _path;
  1204. private Dictionary<string, object> _root;
  1205. [StructLayout(LayoutKind.Explicit)]
  1206. private struct UIntToFloat
  1207. {
  1208. [FieldOffset(0)]
  1209. public float FloatValue;
  1210. [FieldOffset(0)]
  1211. public uint UIntValue;
  1212. }
  1213. public delegate void OnSyncHandler();
  1214. private class CaughtException : Exception
  1215. {
  1216. public CaughtException(string message, Exception ex) : base(message, ex)
  1217. {
  1218. }
  1219. }
  1220. }
  1221. }