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 UniRx; namespace game { public enum ELoginStep { PlayFab, 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 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; } double CreateTotalSeconds(); string Language { get; } Task UpdateLanguage(string code); // 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; } 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; public string GetDefaultName(string id) { return $"Angler#{id[0..5]}"; } public PlayFabUserService() { } 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; } progress?.Invoke(2); return ELoginStep.Done; } private async Task LoginPlayFab() { PlayFabSettings.TitleId = config.Get(GConstant.K_PlayFab_Title, GConstant.V_Debug_PF_Title); // PlayFabSettings.TitleId = 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 { CustomId = Application.identifier; var request = new LoginWithCustomIDRequest { CustomId = CustomId, CreateAccount = true, InfoRequestParameters = info_request_parameters, }; loginResult = await PlayFabClientAsyncAPI.ExecuteWithRetryAsync( () => PlayFabClientAsyncAPI.LoginWithCustomIDAsync(request)); } 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() { ShowLocations = true, } }; var data = await PlayFabClientAsyncAPI.GetPlayerProfileAsync(getPlayerProfileRequest); 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(); await UpdateAvatarUrl(NewPlayerAvatar); sw.Stop(); Debug.Log($"LoginPlayFab update avatar elapsed={sw.Elapsed.TotalSeconds}"); sw.Reset(); } 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(); //InitData should invoke after local time adjusted. InitData(playfabUserData, UserId); return true; } private void InitData(Dictionary datas, string userId) { var comparedData = PlayFabMgr.Instance.CompareDatas(datas, userId); if (comparedData != null) { 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()); 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()); 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 (DateTime.UtcNow - CreateTime).TotalSeconds; } // public virtual async Task GetLinkState(EAccoutType accoutType) // { // await Awaiters.NextFrame; // return false; // } // // public virtual async Task<(int code, int userid)> LinkAccount(EAccoutType accoutType) // { // await Awaiters.NextFrame; // return (1, 0); // } public void UpdateProfile() { } public void UpdateProfileLv() { } #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; } }