Skin.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. using UnityEngine;
  2. using System.Collections;
  3. /// <summary>
  4. /// FSM: http://yuml.me/edit/331d4664
  5. /// </summary>
  6. public class Skin
  7. {
  8. public enum SkinState
  9. {
  10. NULL,
  11. Initialising,
  12. AvailableForApplying,
  13. Applied,
  14. AvailableForPurchase,
  15. Purchasing,
  16. Downloading
  17. }
  18. enum SkinTransition
  19. {
  20. NULL,
  21. AlreadyPurchasedButNotApplied,
  22. AlreadyPurchasedAndApplied,
  23. NotPurchasedYet,
  24. Purchase,
  25. StartDownloading,
  26. PurchaseFailed,
  27. FinishedDownload,
  28. FailedDownload,
  29. Apply,
  30. UnApply
  31. }
  32. public IAPProduct product;
  33. public const string CURRENTLY_APPLIED_SKIN = "CurrentSkin";
  34. const string PURCHASED_KEY_PREFIX = "Purchased";
  35. const string NON_CONSUMABLE_PAYLOAD = "nonconsume";
  36. FSMSystem<SkinTransition, SkinState> _fsm;
  37. float _skinDownloadProgress;
  38. string _pendingTransaction;
  39. public float SkinDownloadProgress { get { return _skinDownloadProgress; } }
  40. public Skin(IAPProduct product)
  41. {
  42. NotificationCenter.AddListener(OnApplySkin, NotificationType.ApplySkin);
  43. this.product = product;
  44. CreateFSM();
  45. //check if it has been purchased, currently applied etc
  46. if (HasPurchasedSkin())
  47. {
  48. if (IsCurrentlyApplied())
  49. {
  50. _fsm.PerformTransition(SkinTransition.AlreadyPurchasedAndApplied);
  51. } else
  52. {
  53. _fsm.PerformTransition(SkinTransition.AlreadyPurchasedButNotApplied);
  54. }
  55. } else
  56. {
  57. _fsm.PerformTransition(SkinTransition.NotPurchasedYet);
  58. }
  59. //#if UNITY_IPHONE
  60. //{
  61. // //StoreKitManager.productPurchaseAwaitingConfirmationEvent += OnProductPurchaseAwaitingConfirmationEvent;
  62. //}
  63. //#endif
  64. }
  65. bool HasPurchasedSkin()
  66. {
  67. if (product.productId == "default")
  68. {
  69. return true;
  70. } else
  71. {
  72. return PlayerPrefs.GetInt(PURCHASED_KEY_PREFIX+product.productId, 0) == 1;
  73. }
  74. }
  75. bool IsCurrentlyApplied()
  76. {
  77. return PlayerPrefs.GetString(CURRENTLY_APPLIED_SKIN, "") == product.productId;
  78. }
  79. #region FSM
  80. void CreateFSM()
  81. {
  82. _fsm = new FSMSystem<SkinTransition, SkinState>("Skin");
  83. var InitialisingState = new FSMState<SkinTransition, SkinState>(SkinState.Initialising);
  84. InitialisingState.AddTransition(SkinTransition.AlreadyPurchasedAndApplied, SkinState.Applied);
  85. InitialisingState.AddTransition(SkinTransition.AlreadyPurchasedButNotApplied, SkinState.AvailableForApplying);
  86. InitialisingState.AddTransition(SkinTransition.NotPurchasedYet, SkinState.AvailableForPurchase);
  87. _fsm.AddState(InitialisingState);
  88. var AvailableForApplyingState = new FSMState<SkinTransition, SkinState>(SkinState.AvailableForApplying);
  89. AvailableForApplyingState.AddTransition(SkinTransition.Apply, SkinState.Applied);
  90. _fsm.AddState(AvailableForApplyingState);
  91. var AppliedState = new FSMState<SkinTransition, SkinState>(SkinState.Applied);
  92. AppliedState.AddTransition(SkinTransition.UnApply, SkinState.AvailableForApplying);
  93. AppliedState.DoBeforeEntering += OnEnteringAppliedState;
  94. _fsm.AddState(AppliedState);
  95. var AvailableForPurchaseState = new FSMState<SkinTransition, SkinState>(SkinState.AvailableForPurchase);
  96. AvailableForPurchaseState.AddTransition(SkinTransition.Purchase, SkinState.Purchasing);
  97. AvailableForPurchaseState.AddTransition(SkinTransition.StartDownloading, SkinState.Downloading);
  98. _fsm.AddState(AvailableForPurchaseState);
  99. var PurchasingState = new FSMState<SkinTransition, SkinState>(SkinState.Purchasing);
  100. PurchasingState.AddTransition(SkinTransition.StartDownloading, SkinState.Downloading);
  101. PurchasingState.AddTransition(SkinTransition.PurchaseFailed, SkinState.AvailableForPurchase);
  102. PurchasingState.DoBeforeEntering += OnEnteringPurchasingState;
  103. PurchasingState.DoBeforeLeaving += OnLeavingPurchasingState;
  104. _fsm.AddState(PurchasingState);
  105. var DownloadingState = new FSMState<SkinTransition, SkinState>(SkinState.Downloading);
  106. DownloadingState.AddTransition(SkinTransition.FinishedDownload, SkinState.AvailableForApplying);
  107. DownloadingState.AddTransition(SkinTransition.FailedDownload, SkinState.AvailableForPurchase);
  108. DownloadingState.DoBeforeEntering += OnEnteringDownloadingState;
  109. DownloadingState.DoBeforeLeaving += OnLeavingDownloadingState;
  110. _fsm.AddState(DownloadingState);
  111. }
  112. void OnEnteringPurchasingState()
  113. {
  114. #if UNITY_EDITOR || UNITY_WEBPLAYER
  115. {
  116. _fsm.PerformTransition(SkinTransition.StartDownloading);
  117. }
  118. //Did not use IAP Combo from Prime31 as it wasn't firing properly when the purchase was cancelled.
  119. #elif UNITY_IPHONE
  120. {
  121. //StoreKitManager.purchaseFailedEvent += OnPurchaseFailed;
  122. //StoreKitManager.purchaseCancelledEvent += OnPurchaseCancelled;
  123. //StoreKitBinding.purchaseProduct(product.productId, 1);
  124. }
  125. #elif UNITY_ANDROID
  126. {
  127. GoogleIABManager.purchaseSucceededEvent += OnGooglePurchaseSucceeded;
  128. GoogleIABManager.purchaseFailedEvent += OnPurchaseFailed;
  129. GoogleIAB.purchaseProduct( product.productId, NON_CONSUMABLE_PAYLOAD );
  130. }
  131. #endif
  132. }
  133. void OnLeavingPurchasingState()
  134. {
  135. //#if UNITY_IPHONE
  136. //{
  137. // StoreKitManager.purchaseFailedEvent -= OnPurchaseFailed;
  138. // StoreKitManager.purchaseCancelledEvent -= OnPurchaseCancelled;
  139. //}
  140. //#elif UNITY_ANDROID
  141. //{
  142. // GoogleIABManager.purchaseSucceededEvent -= OnGooglePurchaseSucceeded;
  143. // GoogleIABManager.purchaseFailedEvent -= OnPurchaseFailed;
  144. //}
  145. //#endif
  146. }
  147. void OnEnteringDownloadingState()
  148. {
  149. NotificationCenter.AddListener(OnSkinDownloadProgress, NotificationType.SkinDownloadProgress);
  150. NotificationCenter.AddListener(OnSkinDownloadCompleted, NotificationType.SkinDownloadCompleted);
  151. NotificationCenter.AddListener(OnSkinDownloadFailed, NotificationType.SkinDownloadFailed);
  152. SkinDownloadManager.Instance.DownloadSkin(product.productId);
  153. }
  154. void OnLeavingDownloadingState()
  155. {
  156. NotificationCenter.RemoveListener(OnSkinDownloadProgress, NotificationType.SkinDownloadProgress);
  157. NotificationCenter.RemoveListener(OnSkinDownloadCompleted, NotificationType.SkinDownloadCompleted);
  158. NotificationCenter.RemoveListener(OnSkinDownloadFailed, NotificationType.SkinDownloadFailed);
  159. }
  160. void OnEnteringAppliedState()
  161. {
  162. if (PlayerPrefs.GetString(CURRENTLY_APPLIED_SKIN, "") == product.productId)
  163. {
  164. return;
  165. }
  166. PlayerPrefs.SetString(CURRENTLY_APPLIED_SKIN, product.productId);
  167. NotificationCenter.Post(NotificationType.ApplySkin, product.productId);
  168. SkinDownloadManager.Instance.ApplyCachedSkin(product.productId);
  169. }
  170. #endregion
  171. #region Download notifications
  172. void OnSkinDownloadProgress(Notification note)
  173. {
  174. object[] parameters = (object[])note.data;
  175. string skinId = (string)parameters[0];
  176. if (skinId == product.productId)
  177. {
  178. _skinDownloadProgress = (float)parameters[1];
  179. }
  180. }
  181. void OnSkinDownloadCompleted(Notification note)
  182. {
  183. string skinId = (string)note.data;
  184. if (skinId == product.productId)
  185. {
  186. AVDebug.Log("Download Complete "+product.productId);
  187. PlayerPrefs.SetInt(PURCHASED_KEY_PREFIX+product.productId, 1);
  188. //#if UNITY_IPHONE
  189. // StoreKitBinding.finishPendingTransaction(_pendingTransaction);
  190. //#endif
  191. _fsm.PerformTransition(SkinTransition.FinishedDownload);
  192. }
  193. }
  194. void OnSkinDownloadFailed(Notification note)
  195. {
  196. string skinId = (string)note.data;
  197. if (skinId == product.productId)
  198. {
  199. AVDebug.Log("Download Failed "+product.productId);
  200. _fsm.PerformTransition(SkinTransition.FailedDownload);
  201. }
  202. }
  203. #endregion
  204. #region Public methods
  205. public SkinState State { get { return _fsm.CurrentStateID; } }
  206. public void Buy()
  207. {
  208. _fsm.PerformTransition(SkinTransition.Purchase);
  209. }
  210. public void Apply()
  211. {
  212. _fsm.PerformTransition(SkinTransition.Apply);
  213. }
  214. public void UnApply()
  215. {
  216. _fsm.PerformTransition(SkinTransition.UnApply);
  217. }
  218. #if UNITY_ANDROID
  219. public void GoogleSaidItsAlreadyPurchased()
  220. {
  221. if (!HasPurchasedSkin())
  222. {
  223. _fsm.PerformTransition(SkinTransition.StartDownloading);
  224. }
  225. }
  226. void OnGooglePurchaseSucceeded(GooglePurchase purchase)
  227. {
  228. if (purchase.productId == product.productId)
  229. {
  230. AVDebug.Log("Google purchase successful "+product.productId);
  231. _fsm.PerformTransition(SkinTransition.StartDownloading);
  232. }
  233. }
  234. #endif
  235. #endregion
  236. #region Store Kit Callbacks
  237. //#if UNITY_IPHONE
  238. // public void OnProductPurchaseAwaitingConfirmationEvent(StoreKitTransaction transaction)
  239. // {
  240. // if (transaction.productIdentifier == product.productId)
  241. // {
  242. // AVDebug.Log("ProductPurchaseAwaitingConfirmationEvent "+transaction.productIdentifier);
  243. // _pendingTransaction = transaction.transactionIdentifier;
  244. // _fsm.PerformTransition(SkinTransition.StartDownloading);
  245. // }
  246. // }
  247. //#endif
  248. void OnPurchaseFailed(string reason)
  249. {
  250. AVDebug.Log("Purchase Failed. Reason: "+reason);
  251. _fsm.PerformTransition(SkinTransition.PurchaseFailed);
  252. }
  253. void OnPurchaseCancelled(string reason)
  254. {
  255. AVDebug.Log("Purchase Cancelled. Reason "+reason);
  256. _fsm.PerformTransition(SkinTransition.PurchaseFailed);
  257. }
  258. #endregion
  259. void OnApplySkin(Notification note)
  260. {
  261. if (State == SkinState.Applied)
  262. {
  263. string skinId = (string)note.data;
  264. if (skinId != product.productId)
  265. {
  266. UnApply();
  267. }
  268. }
  269. }
  270. }