您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

742 行
21 KiB

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using SUISS.Cloud.Boomlagoon.JSON;
  6. using SUISS.Storage;
  7. using UnityEngine;
  8. namespace SUISS.Cloud
  9. {
  10. public class PlayernameController : IPlayernameController
  11. {
  12. public PlayernameController(string sparkSocGameId, int buildVersion, string deviceVendorId)
  13. {
  14. this._sparkSocGameId = sparkSocGameId;
  15. this._buildVersion = buildVersion;
  16. this._deviceVendorId = deviceVendorId;
  17. this._serverUrl = "https://usernames.sparklingsociety.net";
  18. this._loginUrl = "https://usernames.sparklingsociety.net/login/{0}";
  19. }
  20. //[DebuggerBrowsable(DebuggerBrowsableState.Never)]
  21. public event Action LogoutEvent;
  22. protected virtual void FireLogoutEvent()
  23. {
  24. if (this.LogoutEvent != null)
  25. {
  26. this.LogoutEvent();
  27. }
  28. }
  29. public bool IsLinkedToPlayerName
  30. {
  31. get
  32. {
  33. return !string.IsNullOrEmpty(this.PlayerUuid) && !string.IsNullOrEmpty(this.PlayerName);
  34. }
  35. }
  36. public bool IsPlayerLoggedIn
  37. {
  38. get
  39. {
  40. return !string.IsNullOrEmpty(this.RefreshToken);
  41. }
  42. }
  43. public bool IsInstallRegistered
  44. {
  45. get
  46. {
  47. return !string.IsNullOrEmpty(this.InstallSecret) && !string.IsNullOrEmpty(this.InstallUuid);
  48. }
  49. }
  50. public string InstallUuid
  51. {
  52. get
  53. {
  54. if (!this.storage.ContainsKey("installUuid"))
  55. {
  56. this.storage["installUuid"] = string.Empty;
  57. }
  58. return (string)this.storage["installUuid"];
  59. }
  60. private set
  61. {
  62. this.storage["installUuid"] = value;
  63. }
  64. }
  65. public string InstallSecret
  66. {
  67. get
  68. {
  69. if (!this.storage.ContainsKey("installSecret"))
  70. {
  71. this.storage["installSecret"] = string.Empty;
  72. }
  73. return (string)this.storage["installSecret"];
  74. }
  75. private set
  76. {
  77. this.storage["installSecret"] = value;
  78. }
  79. }
  80. public string PlayerUuid
  81. {
  82. get
  83. {
  84. if (!this.storage.ContainsKey("playerUuid"))
  85. {
  86. this.storage["playerUuid"] = string.Empty;
  87. }
  88. return (string)this.storage["playerUuid"];
  89. }
  90. private set
  91. {
  92. this.storage["playerUuid"] = value;
  93. }
  94. }
  95. public string PlayerName
  96. {
  97. get
  98. {
  99. if (!this.storage.ContainsKey("playerName"))
  100. {
  101. this.storage["playerName"] = string.Empty;
  102. }
  103. return (string)this.storage["playerName"];
  104. }
  105. private set
  106. {
  107. this.storage["playerName"] = value;
  108. }
  109. }
  110. private bool HasPlayerAccessToken
  111. {
  112. get
  113. {
  114. return this._playerAccessTokens.ContainsKey("accounts") && this._playerAccessTokens["accounts"] != null && !this._playerAccessTokens["accounts"].HasExpired;
  115. }
  116. }
  117. private bool HasInstallAccessToken
  118. {
  119. get
  120. {
  121. return this._installAccessToken != null && !this._installAccessToken.HasExpired;
  122. }
  123. }
  124. private string DeviceVendorId
  125. {
  126. get
  127. {
  128. return this._deviceVendorId;
  129. }
  130. }
  131. private Dictionary<string, object> storage
  132. {
  133. get
  134. {
  135. return SUISS.Storage.Storage.Get(StorageLifecycle.Forever).GetDictionary("playernameController");
  136. }
  137. }
  138. private string RefreshToken
  139. {
  140. get
  141. {
  142. if (!this.storage.ContainsKey("refreshToken"))
  143. {
  144. this.storage["refreshToken"] = string.Empty;
  145. }
  146. return (string)this.storage["refreshToken"];
  147. }
  148. set
  149. {
  150. this.storage["refreshToken"] = value;
  151. }
  152. }
  153. public bool IsValidPlayername(string playername)
  154. {
  155. return !string.IsNullOrEmpty(playername) && playername.Length > 2 && playername.Length <= 25 && playername.IndexOfAny("{}()[]".ToCharArray()) == -1;
  156. }
  157. public bool IsValidPassword(string password)
  158. {
  159. return !string.IsNullOrEmpty(password) && password.Length > 4;
  160. }
  161. public void LogOutPlayer()
  162. {
  163. foreach (AccessToken accessToken in this._playerAccessTokens.Values)
  164. {
  165. accessToken.Invalidate();
  166. }
  167. this.RefreshToken = string.Empty;
  168. this.FireLogoutEvent();
  169. }
  170. public void ClearInstall()
  171. {
  172. this.LogOutPlayer();
  173. this.InstallUuid = string.Empty;
  174. this.InstallSecret = string.Empty;
  175. this.PlayerUuid = string.Empty;
  176. }
  177. public CloudRequest<IAccessToken, PlayernameErrors?> RequestPlayerAccessToken(string resourceName)
  178. {
  179. return new CloudRequest<IAccessToken, PlayernameErrors?>(this.CoRequestPlayerAccessToken(resourceName));
  180. }
  181. public CloudRequest<IAccessToken, PlayernameErrors?> RequestInstallAccessToken(string resourceName)
  182. {
  183. return new CloudRequest<IAccessToken, PlayernameErrors?>(this.CoRequestInstallAccessToken(resourceName));
  184. }
  185. public CloudRequest<PlayernameErrors?> RegisterInstall()
  186. {
  187. if (this._registeringLock == null)
  188. {
  189. this._registeringLock = new CloudRequest<PlayernameErrors?>(this.CoRegisterInstall());
  190. }
  191. return this._registeringLock;
  192. }
  193. public CloudRequest<PlayernameErrors?> CreatePlayerName(string username, string password)
  194. {
  195. return new CloudRequest<PlayernameErrors?>(this.CoCreateAndLogin(username, password));
  196. }
  197. public CloudRequest<PlayernameErrors?> LinkToPlayerName(string username, string password)
  198. {
  199. return new CloudRequest<PlayernameErrors?>(this.CoLoginAndLink(username, password));
  200. }
  201. private CloudRequest<ApiError> LoginInstall(string installUuid, string installSecret)
  202. {
  203. return new CloudRequest<ApiError>(this.CoLoginInstall(installUuid, installSecret));
  204. }
  205. private IEnumerator CoLoginInstall(string installUuid, string installSecret)
  206. {
  207. if (!this.HasInstallAccessToken)
  208. {
  209. string scope = "read-write";
  210. OAuthRequest request = OAuthRequest.LoginPassword(string.Format(this._loginUrl, "accounts"), installUuid, installSecret, scope);
  211. yield return request;
  212. if (request.Result != null)
  213. {
  214. this._installAccessToken = request.Result.AccessToken;
  215. }
  216. else
  217. {
  218. this._installAccessToken = new AccessToken();
  219. yield return new YieldError<ApiError>(request.Error);
  220. }
  221. }
  222. yield break;
  223. }
  224. private CloudRequest<ApiError> LoginPlayer(string playerRefreshToken)
  225. {
  226. return new CloudRequest<ApiError>(this.CoLoginPlayer(playerRefreshToken));
  227. }
  228. private IEnumerator CoLoginPlayer(string playerRefreshToken)
  229. {
  230. string scope = "read-write";
  231. OAuthRequest request = OAuthRequest.LoginRefreshToken(string.Format(this._loginUrl, "accounts"), playerRefreshToken, scope);
  232. yield return request;
  233. if (request.Result != null)
  234. {
  235. this.UpdateAccessTokenCache("accounts", request.Result.AccessToken);
  236. this.RefreshToken = request.Result.RefreshToken;
  237. }
  238. else
  239. {
  240. if (!request.Error.NoInternet && !request.Error.ServerError)
  241. {
  242. this.LogOutPlayer();
  243. }
  244. yield return new YieldError<ApiError>(request.Error);
  245. }
  246. yield break;
  247. }
  248. private IEnumerator CoRequestPlayerAccessToken(string resourceName)
  249. {
  250. if (this.IsPlayerLoggedIn && this.IsInstallRegistered)
  251. {
  252. string scope = string.Format("read-write:{0}", this.InstallUuid);
  253. OAuthRequest request = OAuthRequest.LoginRefreshToken(string.Format(this._loginUrl, resourceName), this.RefreshToken, scope);
  254. yield return request;
  255. if (request.Result != null)
  256. {
  257. this.RefreshToken = request.Result.RefreshToken;
  258. this.UpdateAccessTokenCache(resourceName, request.Result.AccessToken);
  259. yield return new YieldResult<IAccessToken>(request.Result.AccessToken);
  260. }
  261. else if (request.Error != null)
  262. {
  263. if (request.Error.NoInternet)
  264. {
  265. yield return new YieldError<PlayernameErrors?>(new PlayernameErrors?(PlayernameErrors.NoInternet));
  266. }
  267. else if (request.Error.ServerError)
  268. {
  269. UnityEngine.Debug.LogError("Server error:" + request.Error.Error);
  270. yield return new YieldError<PlayernameErrors?>(new PlayernameErrors?(PlayernameErrors.GeneralError));
  271. }
  272. else
  273. {
  274. this.LogOutPlayer();
  275. yield return new YieldError<PlayernameErrors?>(new PlayernameErrors?(PlayernameErrors.LostValidRefreshToken));
  276. }
  277. }
  278. else
  279. {
  280. this.LogOutPlayer();
  281. yield return new YieldError<PlayernameErrors?>(new PlayernameErrors?(PlayernameErrors.LostValidRefreshToken));
  282. }
  283. }
  284. else
  285. {
  286. yield return new YieldError<PlayernameErrors?>(new PlayernameErrors?(PlayernameErrors.LostValidRefreshToken));
  287. }
  288. yield break;
  289. }
  290. private IEnumerator CoRequestInstallAccessToken(string resourceName)
  291. {
  292. if (this.IsInstallRegistered)
  293. {
  294. string scope = "read-write";
  295. OAuthRequest request = OAuthRequest.LoginPassword(string.Format(this._loginUrl, resourceName), this.InstallUuid, this.InstallSecret, scope);
  296. yield return request;
  297. if (request.Result != null)
  298. {
  299. yield return new YieldResult<IAccessToken>(request.Result.AccessToken);
  300. }
  301. else if (request.Error.NoInternet)
  302. {
  303. yield return new YieldError<PlayernameErrors?>(new PlayernameErrors?(PlayernameErrors.NoInternet));
  304. }
  305. else if (request.Error.ServerError)
  306. {
  307. UnityEngine.Debug.LogError("Server error:" + request.Error.Error);
  308. yield return new YieldError<PlayernameErrors?>(new PlayernameErrors?(PlayernameErrors.GeneralError));
  309. }
  310. else
  311. {
  312. UnityEngine.Debug.LogWarning("Playernames lost Refresh token! Message:" + request.Error.Error);
  313. this.LogOutPlayer();
  314. yield return new YieldError<PlayernameErrors?>(new PlayernameErrors?(PlayernameErrors.LostValidRefreshToken));
  315. }
  316. }
  317. else
  318. {
  319. yield return new YieldError<PlayernameErrors?>(new PlayernameErrors?(PlayernameErrors.LostValidRefreshToken));
  320. }
  321. yield break;
  322. }
  323. private IEnumerator CoLoginAndLink(string username, string password)
  324. {
  325. if (!this.IsInstallRegistered)
  326. {
  327. CloudRequest<PlayernameErrors?> reg = this.RegisterInstall();
  328. yield return reg;
  329. if (reg.Error != null)
  330. {
  331. yield return new YieldError<PlayernameErrors?>(reg.Error);
  332. }
  333. }
  334. CloudRequest<ApiError> log = this.LoginPlayer(username, password);
  335. yield return log;
  336. if (log.Error != null)
  337. {
  338. yield return this.CheckErrors(log.Error);
  339. }
  340. if (!this.IsLinkedToPlayerName || username != this.PlayerName)
  341. {
  342. if (username != this.PlayerName)
  343. {
  344. UnityEngine.Debug.LogWarning("Game already linked to other player! Relinking to new player name.");
  345. }
  346. CloudRequest<ApiError> link = this.LinkInstallToPlayerName(this._playerAccessTokens["accounts"], this.InstallUuid, this.InstallSecret);
  347. yield return link;
  348. if (link.Error != null)
  349. {
  350. yield return this.CheckErrors(link.Error);
  351. }
  352. }
  353. yield break;
  354. }
  355. private IEnumerator CoCreateAndLogin(string username, string password)
  356. {
  357. if (!this.IsInstallRegistered)
  358. {
  359. CloudRequest<PlayernameErrors?> reg = this.RegisterInstall();
  360. yield return reg;
  361. if (reg.Error != null)
  362. {
  363. yield return new YieldError<PlayernameErrors?>(reg.Error);
  364. }
  365. }
  366. if (!this.HasInstallAccessToken)
  367. {
  368. CloudRequest<ApiError> log = this.LoginInstall(this.InstallUuid, this.InstallSecret);
  369. yield return log;
  370. if (log.Error != null)
  371. {
  372. yield return this.CheckErrors(log.Error);
  373. }
  374. }
  375. CloudRequest<ApiError> create = this.CreatePlayer(this._installAccessToken, username, password);
  376. yield return create;
  377. if (create.Error != null)
  378. {
  379. yield return this.CheckErrors(create.Error);
  380. }
  381. CloudRequest<ApiError> loginPlayer = this.LoginPlayer(username, password);
  382. yield return loginPlayer;
  383. if (loginPlayer.Error != null)
  384. {
  385. yield return this.CheckErrors(loginPlayer.Error);
  386. }
  387. yield break;
  388. }
  389. private YieldError<PlayernameErrors?> CheckErrors(ApiError error)
  390. {
  391. if (error.NoInternet)
  392. {
  393. return new YieldError<PlayernameErrors?>(new PlayernameErrors?(PlayernameErrors.NoInternet));
  394. }
  395. if (error.ServerError)
  396. {
  397. UnityEngine.Debug.LogError("Server error:" + error.Error);
  398. return new YieldError<PlayernameErrors?>(new PlayernameErrors?(PlayernameErrors.GeneralError));
  399. }
  400. PlayernameErrors errorCode = (PlayernameErrors)error.ErrorCode;
  401. if (errorCode != PlayernameErrors.DuplicatePlayername && errorCode != PlayernameErrors.ProfanePlayername && errorCode != PlayernameErrors.PlayernameNotFound && errorCode != PlayernameErrors.IncorrectPassword)
  402. {
  403. UnityEngine.Debug.LogError(string.Concat(new object[]
  404. {
  405. "Server returned unexpected error code (",
  406. error.ErrorCode,
  407. "):",
  408. error.Error
  409. }));
  410. return new YieldError<PlayernameErrors?>(new PlayernameErrors?(PlayernameErrors.GeneralError));
  411. }
  412. return new YieldError<PlayernameErrors?>(new PlayernameErrors?((PlayernameErrors)error.ErrorCode));
  413. }
  414. private CloudRequest<ApiError> LoginPlayer(string username, string password)
  415. {
  416. return new CloudRequest<ApiError>(this.CoLoginPlayer(username, password));
  417. }
  418. private IEnumerator CoLoginPlayer(string username, string password)
  419. {
  420. if (this.IsPlayerLoggedIn)
  421. {
  422. this.LogOutPlayer();
  423. }
  424. string scope = "read-write";
  425. OAuthRequest request = OAuthRequest.LoginPassword(string.Format(this._loginUrl, "accounts"), username, password, scope);
  426. yield return request;
  427. if (request.Result != null)
  428. {
  429. this.UpdateAccessTokenCache("accounts", request.Result.AccessToken);
  430. this.RefreshToken = request.Result.RefreshToken;
  431. }
  432. else
  433. {
  434. yield return new YieldError<ApiError>(request.Error);
  435. }
  436. yield break;
  437. }
  438. private IEnumerator CoRegisterInstall()
  439. {
  440. if (this.IsInstallRegistered)
  441. {
  442. UnityEngine.Debug.LogWarning("This install is allready registered. Doing nothing!");
  443. yield break;
  444. }
  445. string url = string.Format("{0}/installs", this._serverUrl);
  446. JSONValue json = this.jsonInstall();
  447. ApiRequest request = ApiRequest.Post(url, json, this._buildVersion.ToString(), this._sparkSocGameId);
  448. yield return request;
  449. if (request.Result != null)
  450. {
  451. JSONValue response = request.Result.Data;
  452. if (response.Type == JSONValueType.Object)
  453. {
  454. JSONObject obj = response.Obj;
  455. this.InstallSecret = obj.GetString("secret");
  456. this.InstallUuid = obj.GetString("sagId");
  457. this._registeringLock = null;
  458. }
  459. else
  460. {
  461. UnityEngine.Debug.LogError(string.Concat(new string[]
  462. {
  463. url,
  464. " returned ",
  465. response.Type.ToString(),
  466. " but was expecting ",
  467. JSONValueType.Object.ToString()
  468. }));
  469. yield return new YieldError<PlayernameErrors?>(new PlayernameErrors?(PlayernameErrors.GeneralError));
  470. }
  471. }
  472. else
  473. {
  474. if (!request.Error.NoInternet)
  475. {
  476. UnityEngine.Debug.LogError("PlayernameController.CoRegisterInstall failed with: " + request.Error.Error);
  477. }
  478. else
  479. {
  480. UnityEngine.Debug.LogWarning(string.Format("PlayernameController.CoRegisterInstall failed with no internet: '{0}'", request.Error.Error));
  481. }
  482. this._registeringLock = null;
  483. }
  484. yield break;
  485. }
  486. private CloudRequest<ApiError> LinkInstallToPlayerName(AccessToken playerAccessToken, string installUuid, string installSecret)
  487. {
  488. return new CloudRequest<ApiError>(this.CoLinkInstallToPlayerName(playerAccessToken, installUuid, installSecret));
  489. }
  490. private IEnumerator CoLinkInstallToPlayerName(IAccessToken playerAccessToken, string installUuid, string installSecret)
  491. {
  492. string url = string.Format("{0}/installs/link/{1}?access_token={2}", this._serverUrl, installUuid, playerAccessToken.Token);
  493. JSONValue json = new JSONValue(new JSONObject
  494. {
  495. {
  496. "install_secret",
  497. new JSONValue(installSecret)
  498. }
  499. });
  500. ApiRequest request = ApiRequest.Post(url, json, this._buildVersion.ToString(), this._sparkSocGameId);
  501. yield return request;
  502. if (request.Result != null)
  503. {
  504. JSONValue response = request.Result.Data;
  505. if (response.Type == JSONValueType.Object)
  506. {
  507. this.PlayerUuid = JSONParse.StringField(response.Obj, "accountUuid", string.Empty);
  508. this.PlayerName = JSONParse.StringField(response.Obj, "playerName", string.Empty);
  509. }
  510. else
  511. {
  512. this.PlayerUuid = string.Empty;
  513. yield return new YieldError<ApiError>(new ApiError
  514. {
  515. Status = 0,
  516. Error = string.Concat(new string[]
  517. {
  518. url,
  519. " returned ",
  520. response.Type.ToString(),
  521. " but was expecting ",
  522. JSONValueType.Object.ToString()
  523. }),
  524. ErrorCode = 0,
  525. ServerError = true
  526. });
  527. }
  528. }
  529. else
  530. {
  531. this.PlayerUuid = string.Empty;
  532. yield return new YieldError<ApiError>(request.Error);
  533. }
  534. yield break;
  535. }
  536. private CloudRequest<ApiError> CreatePlayer(IAccessToken installAccessToken, string username, string password)
  537. {
  538. if (this._creatingPlayerLock == null)
  539. {
  540. this._creatingPlayerLock = new CloudRequest<ApiError>(this.CoCreatePlayerName(installAccessToken, username, password));
  541. }
  542. return this._creatingPlayerLock;
  543. }
  544. private IEnumerator CoCreatePlayerName(IAccessToken installAccessToken, string username, string password)
  545. {
  546. string url = string.Format("{0}/accounts?access_token={1}", this._serverUrl, installAccessToken.Token);
  547. JSONValue json = this.jsonPlayer(username, password, string.Empty, false);
  548. ApiRequest request = ApiRequest.Post(url, json, this._buildVersion.ToString(), this._sparkSocGameId);
  549. yield return request;
  550. if (request.Result != null)
  551. {
  552. JSONValue response = request.Result.Data;
  553. PlayerNameData data = PlayerNameData.fromJson(response);
  554. if (data != null)
  555. {
  556. this.PlayerUuid = data.AccountUuid;
  557. this.PlayerName = data.Playername;
  558. this._creatingPlayerLock = null;
  559. }
  560. else
  561. {
  562. this._creatingPlayerLock = null;
  563. yield return new YieldError<ApiError>(new ApiError
  564. {
  565. Status = 0,
  566. Error = string.Concat(new string[]
  567. {
  568. url,
  569. " returned ",
  570. response.Type.ToString(),
  571. " but was expecting ",
  572. JSONValueType.Object.ToString()
  573. }),
  574. ErrorCode = 0,
  575. ServerError = true
  576. });
  577. }
  578. }
  579. else
  580. {
  581. this._creatingPlayerLock = null;
  582. yield return new YieldError<ApiError>(request.Error);
  583. }
  584. yield break;
  585. }
  586. private JSONValue jsonInstall()
  587. {
  588. return new JSONValue(new JSONObject
  589. {
  590. {
  591. "gameId",
  592. new JSONValue(this._sparkSocGameId)
  593. },
  594. {
  595. "deviceVendorId",
  596. new JSONValue(this.DeviceVendorId)
  597. },
  598. {
  599. "deviceInfo",
  600. this.jsonDeviceInfo()
  601. }
  602. });
  603. }
  604. private JSONValue jsonPlayer(string username, string password, string email, bool aweber)
  605. {
  606. return new JSONValue(new JSONObject
  607. {
  608. {
  609. "username",
  610. new JSONValue(username)
  611. },
  612. {
  613. "email",
  614. new JSONValue(email)
  615. },
  616. {
  617. "password",
  618. new JSONValue(password)
  619. },
  620. {
  621. "aweberSubscription",
  622. new JSONValue(aweber)
  623. }
  624. });
  625. }
  626. private JSONValue jsonDeviceInfo()
  627. {
  628. return new JSONValue(new JSONObject
  629. {
  630. {
  631. "devicePlatform",
  632. new JSONValue(SystemInfo.deviceModel)
  633. },
  634. {
  635. "deviceHardware",
  636. new JSONValue(SystemInfo.deviceModel)
  637. },
  638. {
  639. "deviceOs",
  640. new JSONValue(SystemInfo.operatingSystem)
  641. },
  642. {
  643. "deviceType",
  644. new JSONValue(SystemInfo.deviceType.ToString())
  645. }
  646. });
  647. }
  648. private void UpdateAccessTokenCache(string resource, AccessToken newToken)
  649. {
  650. if (this._playerAccessTokens.ContainsKey(resource) && newToken.Token != this._playerAccessTokens[resource].Token)
  651. {
  652. this._playerAccessTokens[resource].Invalidate();
  653. }
  654. this._playerAccessTokens[resource] = newToken;
  655. }
  656. public const string StorageKey = "playernameController";
  657. public const string RefreshTokenKey = "refreshToken";
  658. public const string AccessTokenKey = "accessToken";
  659. public const string InstallUuidKey = "installUuid";
  660. public const string PlayerUuidKey = "playerUuid";
  661. public const string InstallSecretKey = "installSecret";
  662. public const string PlayerNameKey = "playerName";
  663. private const string InstallsCall = "{0}/installs";
  664. private const string AccountsCall = "{0}/accounts?access_token={1}";
  665. private const string LinkInstallCall = "{0}/installs/link/{1}?access_token={2}";
  666. private const string AccountsResource = "accounts";
  667. private string _sparkSocGameId;
  668. private int _buildVersion;
  669. private string _serverUrl;
  670. private string _loginUrl;
  671. private string _deviceVendorId;
  672. private AccessToken _installAccessToken;
  673. private Dictionary<string, AccessToken> _playerAccessTokens = new Dictionary<string, AccessToken>();
  674. private CloudRequest<ApiError> _creatingPlayerLock;
  675. private CloudRequest<PlayernameErrors?> _registeringLock;
  676. }
  677. }