Files
MinFt/Client/Assets/Scripts/Services/UserService.cs
2026-04-27 12:07:32 +08:00

471 lines
16 KiB
C#

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<ELoginStep> Login(Action<int> progress, bool tyrLoginByToken = true);
void Logout();
bool IsLogin { get; }
bool IsAuthorized { get; }
DateTime LastLoginTime { get; }
DateTime LoginTime { get; }
DateTime CreateTime { get; }
Task<string> ChangeDisplayName(string newName);
string DisplayName { get; }
string AvatarUrl { get; }
Dictionary<string, string> EAccoutUrl { get; }
EntityKey entityKey { get; }
Task<string> UpdateAvatarUrl(string url);
string UserId { get; }
string CustomId { get; }
uint InternalId { get; }
string ContinentCode { get; }
double CreateTotalSeconds();
string Language { get; }
Task<string> UpdateLanguage(string code);
// Task<(int code, int userid)> LinkAccount(EAccoutType accoutType);
// Task<bool> 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<string, string> 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<IDictionary<string, string>> 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<ELoginStep> Login(Action<int> 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<bool> LoginPlayFab()
{
PlayFabSettings.TitleId = config.Get<string>(GConstant.K_PlayFab_Title, GConstant.V_Debug_PF_Title);
// PlayFabSettings.TitleId = GConstant.V_Debug_PF_Title;
PlayFab.Internal.PlayFabWebRequest.SkipCertificateValidation();
var timeout = config.Get<int>(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<ISettingService>();
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<string, UserDataRecord> datas, string userId)
{
var comparedData = PlayFabMgr.Instance.CompareDatas(datas, userId);
if (comparedData != null)
{
GContext.container.Resolve<PlayerData>().LoadPlayerData(comparedData);
OnInitData?.Invoke(comparedData);
}
}
public virtual void Logout()
{
UserId = null;
InternalId = 0;
DisplayName = null;
AvatarUrl = null;
PlayFabClientAPI.ForgetAllCredentials();
}
public virtual async Task<string> 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<string> 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<string> 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<bool> 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<string, PlayInfo> PlayInfos = new Dictionary<string, PlayInfo>();
Dictionary<string, int> PlayLvs = new Dictionary<string, int>();
public async Task<(string, int)> GetPlayLv(string playFabId)
{
if (!PlayLvs.ContainsKey(playFabId))
{
var resultUserData = await PlayFabClientAsyncAPI.GetUserDataAsync(new GetUserDataRequest()
{
PlayFabId = playFabId,
Keys = new List<string>() { "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<PlayerData>().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;
}
}