using System.Threading.Tasks; using asap.core; using PlayFab; using asap.playfab.async; using PlayFab.ClientModels; using System; using System.Collections.Generic; using UnityEngine; using GameCore; using Newtonsoft.Json; using Newtonsoft.Json.Linq; #if UNITY_ANDROID using TapjoyUnity.Internal; #endif using tysdk; using UniRx; using YiDun.Protector; namespace game { public enum ELoginStep { PlayFab, Sdk, Api, Done } public class LoginRequest { public string playerId { get; set; } public PlayerProfile playerProfile { get; set; } } public class PlayerProfile { public int Level { get; set; } public string Avatar { get; set; } public string DisplayName { get; set; } } public class EvtAPISvrLoginSuccess { public string playerId { get; set; } public uint internalId { get; set; } } public class EvtAPISvrUnauthorized { } public interface IUserService { Task Login(Action progress, bool tyrLoginByToken = true); void Logout(); bool IsLogin { get; } bool IsAuthorized { get; } DateTime LastLoginTime { get; } DateTime LoginTime { get; } DateTime CreateTime { get; } Task ChangeDisplayName(string newName); string DisplayName { get; } string AvatarUrl { get; } Dictionary EAccoutUrl { get; } EntityKey entityKey { get; } Task UpdateAvatarUrl(string url); string UserId { get; } string CustomId { get; } uint InternalId { get; } string ContinentCode { get; } //string CountryCode { get; } double CreateTotalSeconds(); string Language { get; } Task UpdateLanguage(string code); /// /// Link sns account /// success return ( code 0, current userid) /// exists return ( code -1, exists account user id) /// fail return ( code 1, 0 ) /// /// sns type [hwGoogle, hwFacebook, hwGuest, Apple] /// code and userid Task<(int code, int userid)> LinkAccount(EAccoutType accoutType); Task GetLinkState(EAccoutType accoutType); void SetPlayerLv(string playFabId, int lv); Task<(string, int)> GetPlayLv(string playFabId); int GetPlayerLv(string playFabId); PlayInfo GetPlayInfo(string id); void ClearPlayInfos(); void SetPlayInfo(string playFabId, string name, string avatarUrl); string GetDefaultName(string id); void UpdateProfile(); void UpdateProfileLv(); } public class PlayFabUserService : IUserService { [Inject] public IConfig config { get; set; } [Inject] public ICustomServerMgr customServerMgr { get; set; } public bool IsLogin => PlayFabClientAPI.IsClientLoggedIn(); public bool IsAuthorized => InternalId != 0; public DateTime LastLoginTime { get; protected set; } public DateTime LoginTime { get; protected set; } public DateTime CreateTime { get; protected set; } public string DisplayName { get; protected set; } public string AvatarUrl { get; protected set; } public Dictionary EAccoutUrl { get; protected set; } public string Language { get; protected set; } public string UserId { get; protected set; } public EntityKey entityKey { get; protected set; } public string CustomId { get; set; } public uint InternalId { get; protected set; } public string ContinentCode { get; protected set; } public string CountryCode { get; protected set; } protected virtual string NewPlayerName => $"Angler#{CustomId}"; protected Action> OnInitData; protected virtual string NewPlayerAvatar => string.Empty; private bool IsApiServerLogin => InternalId != 0; int MMTestValue;//0=>A 原来的 对照组 1=>B 新的实验组 const string MMTestKey = "MMTest"; const string MMTestSubKey = "MMFailParam"; public string GetDefaultName(string id) { return $"Angler#{id[0..5]}"; } public PlayFabUserService() { GContext.OnEvent().Subscribe(_ => LoginApiServer()); } public virtual async Task Login(Action progress, bool tyrLoginByToken = true) { if (IsLogin) { progress?.Invoke(2); return ELoginStep.Done; } if (!PlayFabClientAPI.IsClientLoggedIn()) { if (!await LoginPlayFab()) return ELoginStep.PlayFab; } SetMMTestValue(); GContext.container.Resolve().WaitingForLogin(); OnYinDunLogin(); LoginApiServer(); InitTapJoy(); progress?.Invoke(2); return ELoginStep.Done; } private static void InitTapJoy() { #if UNITY_ANDROID var lastBalanceStr = PlayFabMgr.Instance.GetLocalData("TapJoy_Diamond") ?? ""; Debug.Log($"InitTapJoy -> {lastBalanceStr}"); var lastBalance = int.TryParse(lastBalanceStr, out var temp) ? temp : 0; var tapjoyObject = GameObject.FindObjectOfType(); if (tapjoyObject && tapjoyObject.gameObject && !tapjoyObject.GetComponent()) { var tapjoyHelper = tapjoyObject.gameObject.AddComponent(); GameObject.DontDestroyOnLoad(tapjoyHelper); tapjoyHelper.Init(lastBalance, OnEarnCurrencyName, OnBalance); } return; void OnEarnCurrencyName(string currencyName, int amount) { Debug.Log($"OnEarnCurrencyName -> {currencyName} {amount}"); // var amount = (balance - lastBalance); var diamonds = new ItemData { id = 1005, count = amount }; diamonds.curCount = (ulong)GContext.container.Resolve().GetItemCount(diamonds.id); GContext.container.Resolve().AddItem(diamonds, null); GContext.Publish(new ShowData(new List { diamonds }, RewardType.NormalOne)); GContext.Publish(new ShowData()); #if AGG using (var e = GEvent.GameEvent("tapjoy")) { e.AddContent("item_id", diamonds.id) .AddContent("item_count", diamonds.count); } #endif } void OnBalance(string currencyName, int balance) { Debug.Log($"OnBalance -> {currencyName} {balance}"); // const string tapjoyKey = "TapJoy_Diamond"; // var lastBalanceStr = PlayFabMgr.Instance.GetLocalData(tapjoyKey) ?? ""; // var lastBalance = int.TryParse(lastBalanceStr, out var temp) ? temp : 0; { // PlayFabMgr.Instance.UpdateUserDataValue(tapjoyKey, balance.ToString()); // if (balance > lastBalance) // { // var amount = (balance - lastBalance); // var diamonds = new ItemData { id = 1005, count = amount }; // diamonds.curCount = (ulong)GContext.container.Resolve().GetItemCount(diamonds.id); // GContext.container.Resolve().AddItem(diamonds); // GContext.Publish(new ShowData(new List { diamonds }, RewardType.NormalOne)); // // GContext.Publish(new ShowData(diamonds)); // GContext.Publish(new ShowData()); // } } } #endif } protected async void OnYinDunLogin() { // 开发模式下,先不启用了 if (config != null && (config.Get("DEBUG", "0") == "1" || config.Get("GM", "0") == "1")) { return; } var userService = GContext.container.Resolve(); var yiDunManager = GContext.container.Resolve(); var roleName = userService.DisplayName; var roleId = userService.UserId; var roleAccount = userService.CustomId; var versionData = new { GameVersion = Application.version, AssetVersion = config.Get(GConstant.K_AssetVersion, string.Empty), #if UNITY_ANDROID Channel = GConstant.Yidun_GooglePlayChannel #elif UNITY_IOS Channel = GConstant.Yidun_IOSChannel #endif }; Debug.Log($"JsonUtility.ToJson(versionData) => {JsonConvert.SerializeObject(versionData)}"); var businessId = GConstant.Yidun_AndroidBusinessId; #if UNITY_IOS businessId = GConstant.Yidun_IOSBusinessId; #endif #if (UNITY_ANDROID || UNITY_IOS || UNITY_IPHONE) && !UNITY_EDITOR yiDunManager.SetRoleInfo(businessId, roleId, roleName, roleAccount, null, -1, JsonConvert.SerializeObject(versionData)); yiDunManager.PostRiskCheck(); #endif } void SetMMTestValue() { if (MMTestValue == -1) { //int id = (int)(InternalId / 2) * 2 + 1; //int AB = (int)(id % 8); // convert UserId string to ulong var ulongUserId = ulong.Parse(UserId, System.Globalization.NumberStyles.HexNumber); int AB = (int)(ulongUserId % 16); MMTestValue = AB; PlayFabMgr.Instance.UpdateUserDataValue(MMTestKey, $"{MMTestSubKey}#{MMTestValue}"); } string ab = GContext.container.Resolve().Init(MMTestValue); GEvent.SetUserProp("MMTestValue", ab, true); Debug.Log($"UserId:{UserId} MMTestValue :0b{Convert.ToString(MMTestValue, 2)} MMTestValueString:{ab}"); } public void GMMMT(int value) { MMTestValue = value; PlayFabMgr.Instance.UpdateUserDataValue(MMTestKey, $"{MMTestSubKey}#{MMTestValue}"); string ab = GContext.container.Resolve().Init(MMTestValue); GEvent.SetUserProp("MMTestValue", ab, true); Debug.Log($"UserId:{UserId} MMTestValue :0b{Convert.ToString(MMTestValue, 2)} MMTestValueString:{ab}"); } private async Task LoginPlayFab() { PlayFabSettings.TitleId = config.Get(GConstant.K_PlayFab_Title, GConstant.V_Debug_PF_Title); PlayFab.Internal.PlayFabWebRequest.SkipCertificateValidation(); var timeout = config.Get(GConstant.K_PlayFab_TimeOut, 0); if (timeout != 0) { PlayFabSettings.RequestTimeout = timeout; } var sw = new System.Diagnostics.Stopwatch(); sw.Start(); var info_request_parameters = new GetPlayerCombinedInfoRequestParams { GetUserAccountInfo = true, GetUserData = true, GetPlayerProfile = true, ProfileConstraints = new PlayerProfileViewConstraints() { ShowAvatarUrl = true, ShowDisplayName = true, ShowLocations = true, } }; LoginResult loginResult = null; if (CustomId != string.Empty) { var request = new LoginWithCustomIDRequest { CustomId = CustomId, CreateAccount = true, InfoRequestParameters = info_request_parameters, }; Debug.Log($"[UserService::LoginPlayFab] LoginWithCustomIDAsync customId:{CustomId}"); loginResult = await PlayFabClientAsyncAPI.ExecuteWithRetryAsync( () => PlayFabClientAsyncAPI.LoginWithCustomIDAsync(request)); Debug.Log($"[UserService::LoginPlayFab] LoginWithCustomIDAsync result:{loginResult != null}"); } else { #if UNITY_IOS CustomId = UnityEngine.iOS.Device.advertisingIdentifier; var request = new LoginWithIOSDeviceIDRequest { DeviceId = UnityEngine.iOS.Device.advertisingIdentifier, OS = "iOS", DeviceModel = UnityEngine.iOS.Device.generation.ToString(), CreateAccount = true, InfoRequestParameters = info_request_parameters, }; loginResult = await PlayFabClientAsyncAPI.LoginWithIOSDeviceIDAsync(request); #elif UNITY_ANDROID CustomId = SystemInfo.deviceUniqueIdentifier; var request = new LoginWithAndroidDeviceIDRequest { AndroidDeviceId = SystemInfo.deviceUniqueIdentifier, AndroidDevice = SystemInfo.deviceModel, CreateAccount = true, InfoRequestParameters = info_request_parameters, }; loginResult = await PlayFabClientAsyncAPI.LoginWithAndroidDeviceIDAsync(request); #else CustomId = Application.identifier; var request = new LoginWithCustomIDRequest { AndroidDeviceId = Application.identifier, CreateAccount = true, InfoRequestParameters = info_request_parameters, }; loginResult = await PlayFabClientAsyncAPI.ExecuteWithRetryAsync( () => PlayFabClientAsyncAPI.LoginWithCustomIDAsync(request)); #endif } sw.Stop(); if (loginResult == null) return false; Debug.Log($"LoginPlayFab elapsed={sw.Elapsed.TotalSeconds}"); sw.Reset(); entityKey = loginResult.EntityToken.Entity; if (!loginResult.NewlyCreated) { DisplayName = loginResult.InfoResultPayload.PlayerProfile?.DisplayName ?? string.Empty; AvatarUrl = loginResult.InfoResultPayload.PlayerProfile?.AvatarUrl ?? string.Empty; ContinentCode = loginResult.InfoResultPayload.PlayerProfile?.Locations[0]?.ContinentCode?.ToString() ?? "UNKNOW"; CountryCode = loginResult.InfoResultPayload.PlayerProfile?.Locations[0]?.CountryCode?.ToString(); config.Set("NewlyCreated", false); } else { sw.Start(); GetPlayerProfileRequest getPlayerProfileRequest = new GetPlayerProfileRequest() { ProfileConstraints = new PlayerProfileViewConstraints() { //ShowAvatarUrl = true, //ShowDisplayName = true, ShowLocations = true, } }; var data = await PlayFabClientAsyncAPI.GetPlayerProfileAsync(getPlayerProfileRequest); //DisplayName = data.PlayerProfile.DisplayName; //AvatarUrl = data.PlayerProfile.AvatarUrl; ContinentCode = data?.PlayerProfile.Locations[0]?.ContinentCode?.ToString() ?? "UNKNOW"; CountryCode = data?.PlayerProfile.Locations[0]?.CountryCode?.ToString(); sw.Stop(); Debug.Log($"LoginPlayFab GetPlayerProfile elapsed={sw.Elapsed.TotalSeconds}"); sw.Reset(); config.Set("NewlyCreated", true); } UserId = loginResult.PlayFabId; if (string.IsNullOrEmpty(DisplayName)) { sw.Start(); DisplayName = await ChangeDisplayName(NewPlayerName); sw.Stop(); Debug.Log($"LoginPlayFab ChangeDisplayName elapsed={sw.Elapsed.TotalSeconds}"); sw.Reset(); } if (string.IsNullOrEmpty(AvatarUrl)) { sw.Start(); /*AvatarUrl = */ await UpdateAvatarUrl(NewPlayerAvatar); sw.Stop(); Debug.Log($"LoginPlayFab update avatar elapsed={sw.Elapsed.TotalSeconds}"); sw.Reset(); } //BuglyAgent.SetUserId(UserId); var setting = GContext.container.Resolve(); await UpdateLanguage(setting.Lang); var playfabUserData = loginResult.InfoResultPayload?.UserData; CreateTime = loginResult.InfoResultPayload.AccountInfo.Created.ToUniversalTime(); var tokenExpiration = loginResult.EntityToken.TokenExpiration?.ToUniversalTime(); if (tokenExpiration.HasValue) { LoginTime = tokenExpiration.Value.ToUniversalTime() - TimeSpan.FromDays(1); } else { LoginTime = DateTime.UtcNow; } if (loginResult.LastLoginTime.HasValue) LastLoginTime = loginResult.LastLoginTime.Value.ToUniversalTime(); ZZTimeHelper.AdjustTime(LoginTime); ZZTimeHelper.WathForcusChange(); //InitData should invoke after local time adjusted. //save login time to local storage. InitData(playfabUserData, UserId); return true; } private bool tryLoginApiSvr = false; private async void LoginApiServer() { if (tryLoginApiSvr) return; tryLoginApiSvr = true; var sw = new System.Diagnostics.Stopwatch(); PlayerProfile playerProfile = new PlayerProfile() { Avatar = AvatarUrl, DisplayName = DisplayName, Level = GContext.container.Resolve().lv }; LoginRequest loginRequest = new LoginRequest() { playerId = UserId, playerProfile = playerProfile }; try { var apiLoginResponse = await customServerMgr.AccountRequest("Login", loginRequest); sw.Stop(); Debug.Log($"LoginApiServer elapsed={sw.Elapsed.TotalSeconds}"); if (string.IsNullOrEmpty(apiLoginResponse)) { tryLoginApiSvr = false; return; } var result = JObject.Parse(apiLoginResponse); if ((byte)result["state"] == 0) { InternalId = (uint)result["internalId"]; GContext.Publish(new EvtAPISvrLoginSuccess() { playerId = UserId, internalId = InternalId }); } else { InternalId = 0; } } catch (Exception e) { Debug.LogError(e); InternalId = 0; } tryLoginApiSvr = false; } public async virtual Task<(int code, int userid)> LinkAccount(EAccoutType accoutType) { await Awaiters.NextFrame; //测试 //#if UNITY_EDITOR // var _accountInfo = new TYSdkFacade.AccountInfo() // { // channel = accoutType, // avatar = "https://tse2-mm.cn.bing.net/th/id/OIP-C.s4x0YU7qC-oat3mnyubG5gAAAA?rs=1&pid=ImgDetMain", // }; // AvatarToPF(_accountInfo); // if (_accountInfo.channel == EAccoutType.hwFacebook) // { // _ = UpdateAvatarUrl(_accountInfo.avatar); // } //#endif return (1,0); } protected void AvatarToPF(TYSdkFacade.AccountInfo accountInfo) { if (accountInfo != null && (accountInfo.channel == EAccoutType.hwFacebook || accountInfo.channel == EAccoutType.hwGoogle) && !string.IsNullOrEmpty(accountInfo.avatar)) { if (EAccoutUrl == null) { EAccoutUrl = new Dictionary(); } EAccoutUrl[accountInfo.channel.ToString()] = accountInfo.avatar; string EAccoutUrlStr = Newtonsoft.Json.JsonConvert.SerializeObject(EAccoutUrl); PlayFabMgr.Instance.UpdateUserDataValue("EAccoutUrl", EAccoutUrlStr); } } private void InitData(Dictionary datas, string userId) { var comparedData = PlayFabMgr.Instance.CompareDatas(datas, userId); if (comparedData != null) { MMTestValue = 0; if (!comparedData.ContainsKey(MMTestKey)) { if (config.Get("NewlyCreated", false)) { //新用户设置MMTest MMTestValue = -1; } else { //老用户设置MMTest PlayFabMgr.Instance.UpdateUserDataValue(MMTestKey, $"{MMTestSubKey}#{MMTestValue}"); } } else { string mmTestValue = comparedData[MMTestKey]; string[] mmTestValueData = mmTestValue.Split('#'); //if (mmTestValueData.Length > 1 && mmTestValueData[0] == MMTestSubOldKey) //{ // int.TryParse(mmTestValueData[1], out int value); // MMTestValue = value & 0b101; // //升级老用户数据 // PlayFabMgr.Instance.UpdateUserDataValue(MMTestKey, $"{MMTestSubKey}#{MMTestValue}"); //} //else if (mmTestValueData.Length > 1 && mmTestValueData[0] == MMTestSubKey) { int.TryParse(mmTestValueData[1], out int value); MMTestValue = value; } else { MMTestValue = 0; PlayFabMgr.Instance.UpdateUserDataValue(MMTestKey, $"{MMTestSubKey}#{MMTestValue}"); } } GContext.container.Resolve().LoadPlayerData(comparedData); OnInitData?.Invoke(comparedData); } } public virtual void Logout() { UserId = null; InternalId = 0; DisplayName = null; AvatarUrl = null; PlayFabClientAPI.ForgetAllCredentials(); } public virtual async Task ChangeDisplayName(string newName) { var originName = string.IsNullOrEmpty(DisplayName) ? NewPlayerName : DisplayName; var result = await PlayFabClientAsyncAPI.UpdateUserTitleDisplayNameAsync(new UpdateUserTitleDisplayNameRequest { DisplayName = newName }); if (result == null) return originName; DisplayName = result.DisplayName; GContext.Publish(new ChangeAvatarEvent()); UpdateProfileName(); return DisplayName; } public virtual async Task UpdateAvatarUrl(string url) { var originUrl = AvatarUrl; Debug.Log("UpdateAvatarUrlAsync originUrl:" + originUrl + " url " + url); if (string.IsNullOrEmpty(url)) return originUrl; if (url == originUrl) { return originUrl; } var result = await PlayFabClientAsyncAPI.UpdateAvatarUrlAsync(new UpdateAvatarUrlRequest { ImageUrl = url }); Debug.Log("UpdateAvatarUrlAsync :" + result); if (result == null) return originUrl; AvatarUrl = url; GContext.Publish(new ChangeAvatarEvent()); UpdateProfileAvatar(); return url; } public virtual async Task UpdateLanguage(string code) { if (Language == code) { return Language; } PlayFab.ProfilesModels.SetProfileLanguageRequest setProfileLanguageRequest = new PlayFab.ProfilesModels.SetProfileLanguageRequest() { Language = code.Replace('_', '-') }; var result = await PlayFabProfilesAsyncAPI.SetProfileLanguageAsync(setProfileLanguageRequest); if (result != null) Language = code; return Language; } public double CreateTotalSeconds() { return (ZZTimeHelper.UtcNow() - CreateTime).TotalSeconds; } public virtual async Task GetLinkState(EAccoutType accoutType) { await Awaiters.NextFrame; return false; } public void UpdateProfile() { PlayerProfile playerProfile = new PlayerProfile(); playerProfile.Avatar = AvatarUrl; playerProfile.DisplayName = DisplayName; playerProfile.Level = GContext.container.Resolve().lv; LoginRequest loginRequest = new LoginRequest() { playerId = UserId, playerProfile = playerProfile }; customServerMgr.AccountRequest("UpdateProfile", loginRequest); } public void UpdateProfileLv() { PlayerProfile playerProfile = new PlayerProfile(); playerProfile.Level = GContext.container.Resolve().lv; LoginRequest loginRequest = new LoginRequest() { playerId = UserId, playerProfile = playerProfile }; customServerMgr.AccountRequest("UpdateProfile", loginRequest); } void UpdateProfileName() { PlayerProfile playerProfile = new PlayerProfile(); playerProfile.DisplayName = DisplayName; LoginRequest loginRequest = new LoginRequest() { playerId = UserId, playerProfile = playerProfile }; customServerMgr.AccountRequest("UpdateProfile", loginRequest); } void UpdateProfileAvatar() { PlayerProfile playerProfile = new PlayerProfile(); playerProfile.Avatar = AvatarUrl; LoginRequest loginRequest = new LoginRequest() { playerId = UserId, playerProfile = playerProfile }; customServerMgr.AccountRequest("UpdateProfile", loginRequest); } #region 其他玩家头像昵称缓存 Dictionary PlayInfos = new Dictionary(); Dictionary PlayLvs = new Dictionary(); public async Task<(string, int)> GetPlayLv(string playFabId) { if (!PlayLvs.ContainsKey(playFabId)) { var resultUserData = await PlayFabClientAsyncAPI.GetUserDataAsync(new GetUserDataRequest() { PlayFabId = playFabId, Keys = new List() { "Lv" } }); if (resultUserData != null) { string level = resultUserData.Data.TryGetValue("Lv", out var value) ? value.Value : "1"; PlayLvs[playFabId] = int.Parse(level); } } int lv = PlayLvs[playFabId]; return (playFabId, lv); } public int GetPlayerLv(string playFabId) { return PlayLvs.ContainsKey(playFabId) ? PlayLvs[playFabId] : 1; } public void SetPlayerLv(string playFabId, int lv) { if (playFabId == UserId) { lv = GContext.container.Resolve().lv; } PlayLvs[playFabId] = lv; } public void ClearPlayInfos() { PlayInfos.Clear(); PlayLvs.Clear(); } public PlayInfo GetPlayInfo(string id) { if (string.IsNullOrEmpty(id)) { return null; } if (!PlayInfos.ContainsKey(id)) { PlayInfo playInfo = new PlayInfo(); playInfo.name = GetDefaultName(id); PlayInfos.Add(id, playInfo); SetPlayInfo(id, playInfo); } return PlayInfos[id]; } async void SetPlayInfo(string playFabId, PlayInfo playInfo) { if (playFabId == UserId) { playInfo.name = DisplayName; playInfo.avatarUrl = AvatarUrl; GContext.Publish(new GetClubPlayInfoEvent() { id = playFabId, name = playInfo.name, avatarUrl = playInfo.avatarUrl }); return; } var resultUserTitle = await PlayFabClientAsyncAPI.GetPlayerProfileAsync(new GetPlayerProfileRequest() { PlayFabId = playFabId, ProfileConstraints = new PlayerProfileViewConstraints() { ShowDisplayName = true, ShowLocations = true, ShowAvatarUrl = true, } }); if (resultUserTitle?.PlayerProfile != null) { if (!string.IsNullOrEmpty(resultUserTitle?.PlayerProfile.DisplayName)) { playInfo.name = resultUserTitle?.PlayerProfile.DisplayName; } playInfo.avatarUrl = resultUserTitle?.PlayerProfile.AvatarUrl; GContext.Publish(new GetClubPlayInfoEvent() { id = playFabId, name = playInfo.name, avatarUrl = playInfo.avatarUrl }); } } public void SetPlayInfo(string playFabId, string name, string avatarUrl) { if (string.IsNullOrEmpty(name)) { name = GetDefaultName(playFabId); } PlayInfo playInfo = new PlayInfo(); playInfo.name = name; playInfo.avatarUrl = avatarUrl; PlayInfos[playFabId] = playInfo; } #endregion 其他玩家头像昵称缓存 } public class PlayInfo { public string name; public string avatarUrl; } }