Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

418 linhas
16 KiB

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using SUISS.Storage;
  5. using UnityEngine;
  6. using UnityEngine.Purchasing;
  7. namespace CIG
  8. {
  9. public class IAPCatalog<T> where T : StoreProduct
  10. {
  11. public IAPCatalog(CIGWebService webService, Func<Dictionary<string, object>, T> storeProductFactory)
  12. {
  13. this._webService = webService;
  14. this._storeProductFactory = storeProductFactory;
  15. this.LoadFromStorage();
  16. this.LoadDefaultPricePoints();
  17. }
  18. private static string DEFAULT_PRICEPOINTS_ASSET_NAME
  19. {
  20. get
  21. {
  22. return "defaultpricepoints-android";
  23. }
  24. }
  25. public IEnumerator UpdatePricePoints()
  26. {
  27. if (this.AreCachedPricePointsOutDated() && this._webService != null)
  28. {
  29. yield return this._webService.WWWWithTimeout(this._webService.PricePoints(), delegate (CIGWebService.WWWResponse response)
  30. {
  31. if (!response.TimedOut)
  32. {
  33. if (string.IsNullOrEmpty(response.Error) && !string.IsNullOrEmpty(response.Text))
  34. {
  35. List<Dictionary<string, object>> productMetadata;
  36. int num;
  37. if (this.ValidatePricePoints(response.Text, out productMetadata, out num))
  38. {
  39. this.UpdateRemoteProducts(productMetadata);
  40. }
  41. else
  42. {
  43. UnityEngine.Debug.LogError("Invalid pricepoints received. - Not using them.");
  44. }
  45. }
  46. else
  47. {
  48. UnityEngine.Debug.LogErrorFormat("Error downloading pricepoints. {0}", new object[]
  49. {
  50. response.Text
  51. });
  52. }
  53. }
  54. else
  55. {
  56. UnityEngine.Debug.LogErrorFormat("Error downloading pricepoints: Timedout", new object[0]);
  57. }
  58. }, 5f);
  59. }
  60. yield break;
  61. }
  62. public void UpdateProducts(Product[] products)
  63. {
  64. int num = products.Length;
  65. for (int i = 0; i < num; i++)
  66. {
  67. Product product = products[i];
  68. T t = this.FindProduct(product.definition.id);
  69. if (t != null)
  70. {
  71. Dictionary<string, object> dictionary = t.Serialize();
  72. dictionary["ProductTitle"] = product.metadata.localizedTitle;
  73. dictionary["ProductDescription"] = product.metadata.localizedDescription;
  74. dictionary["ProductCurrencyCode"] = product.metadata.isoCurrencyCode;
  75. dictionary["ProductFormattedPrice"] = "99";
  76. dictionary["ProductPrice"] = product.metadata.localizedPrice;
  77. this.AddOrUpdateProduct(dictionary);
  78. }
  79. }
  80. this.SaveToStorage();
  81. }
  82. public T FindProduct(string identifier)
  83. {
  84. return this._products.Find((T x) => x.Identifier == identifier);
  85. }
  86. public T FindProduct(Predicate<T> predicate)
  87. {
  88. T[] availableProducts = this.GetAvailableProducts(predicate);
  89. return (availableProducts.Length <= 0) ? ((T)((object)null)) : availableProducts[0];
  90. }
  91. public T[] GetAvailableProducts(Predicate<T> predicate)
  92. {
  93. List<T> list = new List<T>();
  94. int count = this._products.Count;
  95. for (int i = 0; i < count; i++)
  96. {
  97. T t = this._products[i];
  98. if (t.Available && predicate(t))
  99. {
  100. list.Add(t);
  101. }
  102. }
  103. list.Sort();
  104. return list.ToArray();
  105. }
  106. public T[] AvailableProducts
  107. {
  108. get
  109. {
  110. return this._products.FindAll((T x) => x.Available).ToArray();
  111. }
  112. }
  113. private T AddOrUpdateProduct(Dictionary<string, object> productMetadata)
  114. {
  115. T t = this.FindProduct((string)productMetadata["ProductIdentifier"]);
  116. if (t != null)
  117. {
  118. t.Update(productMetadata);
  119. }
  120. else
  121. {
  122. t = this._storeProductFactory(productMetadata);
  123. this._products.Add(t);
  124. }
  125. return t;
  126. }
  127. private void LoadDefaultPricePoints()
  128. {
  129. int num = -1;
  130. object obj;
  131. if (this.storage.TryGetValue("DefaultPricePointsVersionKey", out obj) && obj is int)
  132. {
  133. num = (int)obj;
  134. }
  135. TextAsset textAsset = Resources.Load<TextAsset>(IAPCatalog<T>.DEFAULT_PRICEPOINTS_ASSET_NAME);
  136. if (textAsset == null)
  137. {
  138. UnityEngine.Debug.LogErrorFormat("Unable to open TextAsset {0}.", new object[]
  139. {
  140. IAPCatalog<T>.DEFAULT_PRICEPOINTS_ASSET_NAME
  141. });
  142. return;
  143. }
  144. List<Dictionary<string, object>> productMetadata;
  145. int num2;
  146. if (!this.ValidatePricePoints(textAsset.text, out productMetadata, out num2))
  147. {
  148. UnityEngine.Debug.LogWarningFormat("Invalid default pricepoints. - Not using them.", new object[0]);
  149. return;
  150. }
  151. if (num != -1 && num2 <= num)
  152. {
  153. return;
  154. }
  155. this.UpdateProducts(productMetadata);
  156. if (!this.storage.ContainsKey("DefaultPricePointsVersionKey"))
  157. {
  158. this.storage.Add("DefaultPricePointsVersionKey", -1);
  159. }
  160. this.storage["DefaultPricePointsVersionKey"] = num2;
  161. this.SaveToStorage();
  162. }
  163. private void UpdateRemoteProducts(List<Dictionary<string, object>> productMetadata)
  164. {
  165. this.UpdateProducts(productMetadata);
  166. if (!this.storage.ContainsKey("GameVersionKey"))
  167. {
  168. this.storage.Add("GameVersionKey", string.Empty);
  169. }
  170. if (!this.storage.ContainsKey("CacheDateTimeKey"))
  171. {
  172. this.storage.Add("CacheDateTimeKey", 0L);
  173. }
  174. this.storage["GameVersionKey"] = "3.0.6";
  175. this.storage["CacheDateTimeKey"] = DateTime.UtcNow.ToBinary();
  176. this.SaveToStorage();
  177. }
  178. private void UpdateProducts(List<Dictionary<string, object>> productMetadata)
  179. {
  180. int count = this._products.Count;
  181. for (int i = 0; i < count; i++)
  182. {
  183. T t = this._products[i];
  184. t.Available = false;
  185. }
  186. count = productMetadata.Count;
  187. for (int j = 0; j < count; j++)
  188. {
  189. this.AddOrUpdateProduct(productMetadata[j]);
  190. }
  191. }
  192. private bool AreCachedPricePointsOutDated()
  193. {
  194. object obj;
  195. if (!this.storage.TryGetValue("GameVersionKey", out obj))
  196. {
  197. return true;
  198. }
  199. if (string.IsNullOrEmpty(obj as string))
  200. {
  201. return true;
  202. }
  203. if ((string)obj != "3.0.6")
  204. {
  205. return true;
  206. }
  207. if (!this.storage.TryGetValue("CacheDateTimeKey", out obj))
  208. {
  209. return true;
  210. }
  211. if (!(obj is long))
  212. {
  213. return true;
  214. }
  215. DateTime d = DateTime.FromBinary((long)obj);
  216. return DateTime.UtcNow - d > IAPCatalog<T>.PRICEPOINTS_EXPIRATIONTIME;
  217. }
  218. private bool ValidatePricePoints(string pricepointsRawText, out List<Dictionary<string, object>> productMetadata, out int version)
  219. {
  220. productMetadata = IAPCatalog<T>.ParsePricePoints(pricepointsRawText, out version);
  221. if (productMetadata.Count == 0)
  222. {
  223. return false;
  224. }
  225. Dictionary<string, object> dictionary = productMetadata[0];
  226. return dictionary.ContainsKey("ProductIdentifier") && dictionary.ContainsKey("ProductPrice") && dictionary.ContainsKey("CustomProperties");
  227. }
  228. private static List<Dictionary<string, object>> ParsePricePoints(string pricePoints, out int version)
  229. {
  230. version = -1;
  231. List<Dictionary<string, object>> list = new List<Dictionary<string, object>>();
  232. if (string.IsNullOrEmpty(pricePoints))
  233. {
  234. return list;
  235. }
  236. Dictionary<string, string> dictionary = new Dictionary<string, string>();
  237. foreach (string text in pricePoints.Split(new char[]
  238. {
  239. '\n'
  240. }))
  241. {
  242. int num = text.IndexOf('=');
  243. if (num >= 0)
  244. {
  245. string text2 = text.Substring(0, num).Trim();
  246. string value = text.Substring(num + 1).Trim();
  247. if (dictionary.ContainsKey(text2))
  248. {
  249. UnityEngine.Debug.LogWarningFormat("Result dictionary already contains key '{0}'", new object[]
  250. {
  251. text2
  252. });
  253. }
  254. dictionary[text2] = value;
  255. }
  256. }
  257. string objA = null;
  258. foreach (KeyValuePair<string, string> keyValuePair in dictionary)
  259. {
  260. if (keyValuePair.Key == "version")
  261. {
  262. if (!int.TryParse(keyValuePair.Value, out version))
  263. {
  264. UnityEngine.Debug.LogWarningFormat("Failed to parse pricepoints version '{0}' to int.", new object[]
  265. {
  266. keyValuePair.Value
  267. });
  268. }
  269. }
  270. else
  271. {
  272. int num2 = keyValuePair.Key.LastIndexOf('.');
  273. if (num2 >= 0)
  274. {
  275. string text3 = keyValuePair.Key.Substring(0, num2);
  276. string text4 = keyValuePair.Key.Substring(num2 + 1, keyValuePair.Key.Length - num2 - 1);
  277. Dictionary<string, object> dictionary2;
  278. Dictionary<string, string> dictionary3;
  279. if (!object.Equals(objA, text3))
  280. {
  281. dictionary2 = new Dictionary<string, object>();
  282. dictionary3 = new Dictionary<string, string>();
  283. dictionary2.Add("CustomProperties", dictionary3);
  284. list.Add(dictionary2);
  285. objA = text3;
  286. }
  287. else
  288. {
  289. dictionary2 = list[list.Count - 1];
  290. dictionary3 = (Dictionary<string, string>)dictionary2["CustomProperties"];
  291. }
  292. if (text4.Equals("name"))
  293. {
  294. dictionary2["ProductIdentifier"] = keyValuePair.Value;
  295. }
  296. else if (text4.Equals("dollar"))
  297. {
  298. decimal num3;
  299. if (decimal.TryParse(keyValuePair.Value, out num3))
  300. {
  301. dictionary2["ProductPrice"] = num3;
  302. dictionary2["ProductDollarPrice"] = num3;
  303. dictionary2["ProductFormattedPrice"] = num3.ToString("0.00") + "元";//TODODO 价格在defaultpricepoints-android这个文件里
  304. dictionary2["ProductCurrencyCode"] = "USD";
  305. }
  306. }
  307. else if (text4.Equals("euro"))
  308. {
  309. decimal num4;
  310. if (decimal.TryParse(keyValuePair.Value, out num4))
  311. {
  312. dictionary2["ProductPrice"] = num4;
  313. dictionary2["ProductEuroPrice"] = num4;
  314. dictionary2["ProductFormattedPrice"] = num4.ToString("0.00") + "元";//TODODO 价格在defaultpricepoints-android这个文件里
  315. dictionary2["ProductCurrencyCode"] = "EUR";
  316. }
  317. }
  318. else if (text4.Equals("description"))
  319. {
  320. dictionary2["ProductDescription"] = keyValuePair.Value;
  321. }
  322. else if (text4.Equals("available"))
  323. {
  324. bool flag;
  325. if (bool.TryParse(keyValuePair.Value, out flag))
  326. {
  327. dictionary2["Available"] = flag;
  328. }
  329. }
  330. else
  331. {
  332. dictionary3.Add(text4, keyValuePair.Value);
  333. }
  334. }
  335. }
  336. }
  337. return list;
  338. }
  339. private void SaveToStorage()
  340. {
  341. List<object> list = new List<object>();
  342. for (int i = 0; i < this._products.Count; i++)
  343. {
  344. List<object> list2 = list;
  345. T t = this._products[i];
  346. list2.Add(t.Serialize());
  347. }
  348. if (!this.storage.ContainsKey("StoreProductsKey"))
  349. {
  350. this.storage.Add("StoreProductsKey", list);
  351. }
  352. else
  353. {
  354. this.storage["StoreProductsKey"] = list;
  355. }
  356. Storage.SaveLifecycle(StorageLifecycle.Purchases, false);
  357. }
  358. private void LoadFromStorage()
  359. {
  360. if (this.storage.ContainsKey("StoreProductsKey"))
  361. {
  362. List<object> list = (List<object>)this.storage["StoreProductsKey"];
  363. for (int i = 0; i < list.Count; i++)
  364. {
  365. this.AddOrUpdateProduct((Dictionary<string, object>)list[i]);
  366. }
  367. }
  368. }
  369. private Dictionary<string, object> storage
  370. {
  371. get
  372. {
  373. return Storage.Get(StorageLifecycle.Purchases).GetDictionary("IAPCatalogStorage");
  374. }
  375. }
  376. private const string STORE_PRODUCTS_KEY = "StoreProductsKey";
  377. private const string GAME_VERSION_KEY = "GameVersionKey";
  378. private const string CACHE_DATETIME_KEY = "CacheDateTimeKey";
  379. private const string DEFAULT_PRICEPOINTS_VERSION_KEY = "DefaultPricePointsVersionKey";
  380. private const StorageLifecycle IAPCATALOG_LIFECYCLE = StorageLifecycle.Purchases;
  381. private const string IAPCATALOG_KEY = "IAPCatalogStorage";
  382. private static readonly TimeSpan PRICEPOINTS_EXPIRATIONTIME = new TimeSpan(1, 0, 0, 0);
  383. private const string PRICE_POINTS_VERSION_KEY = "version";
  384. private Func<Dictionary<string, object>, T> _storeProductFactory;
  385. private CIGWebService _webService;
  386. private List<T> _products = new List<T>();
  387. }
  388. }