using System; using Epic.OnlineServices; using Epic.OnlineServices.Auth; using Epic.OnlineServices.Connect; using Facepunch.Steamworks; using RoR2.ConVar; namespace RoR2; public class EOSLoginManager { public enum EOSLoginState { None, AttemptingLogin, AttemptingLink, FailedLogin, FailedLink, Success } public static EOSLoginManager instance = null; public static readonly BoolConVar cvLinkEOSAccount = new BoolConVar("eos_link_account", ConVarFlags.None, "0", "trigger the account linking process"); public LoginCredentialType _loginCredentialType = LoginCredentialType.ExchangeCode; public string _loginCredentialId; public string _loginCredentialToken; private bool showCredentialPopup; public static EpicAccountId loggedInAuthId = null; public static ProductUserId loggedInProductId = null; public static PlatformID loggedInUserID; private ConnectInterface connectInterface; private static string ticket; public static EOSLoginState loginState { get; private set; } = EOSLoginState.None; public static event Action OnAuthLoggedIn; public static event Action OnConnectLoggedIn; public static bool IsWaitingOnLogin() { return loginState != EOSLoginState.Success; } public void TryLogin() { instance = this; RoR2Application.onUpdate += OnUpdate; ExternalAuthLogin_Steam(); } private void OnUpdate() { if (cvLinkEOSAccount.value && !IsWaitingOnLogin()) { StartSteamLoginWithDefaultOptions(attemptAccountLink: true); } } private void OnSteamworksInitialized() { UpdateSessionAuthTicket(); SteamworksClientManager.onLoaded -= OnSteamworksInitialized; } private void UpdateSessionAuthTicket() { ticket = Client.Instance.Auth.GetAuthSessionTicket().Data.ToHexString(); StartSteamLoginWithDefaultOptions(); } public void ExternalAuthLogin_Steam() { if (Client.Instance != null) { OnSteamworksInitialized(); } else { SteamworksClientManager.onLoaded += OnSteamworksInitialized; } } public void StartSteamLoginWithDefaultOptions(bool attemptAccountLink = false) { Epic.OnlineServices.Auth.LoginOptions loginOptions = default(Epic.OnlineServices.Auth.LoginOptions); loginOptions.Credentials = new Epic.OnlineServices.Auth.Credentials { Type = LoginCredentialType.ExternalAuth, Token = ticket, ExternalType = ExternalCredentialType.SteamSessionTicket }; loginOptions.ScopeFlags = AuthScopeFlags.BasicProfile | AuthScopeFlags.FriendsList | AuthScopeFlags.Presence; Epic.OnlineServices.Auth.LoginOptions loginOptions2 = loginOptions; StartEGSLogin(loginOptions2, attemptAccountLink); } private void StartEGSLoginWithDefaultOptions() { Epic.OnlineServices.Auth.LoginOptions loginOptions = default(Epic.OnlineServices.Auth.LoginOptions); loginOptions.Credentials = new Epic.OnlineServices.Auth.Credentials { Type = _loginCredentialType, Id = _loginCredentialId, Token = _loginCredentialToken }; loginOptions.ScopeFlags = AuthScopeFlags.BasicProfile | AuthScopeFlags.FriendsList | AuthScopeFlags.Presence; Epic.OnlineServices.Auth.LoginOptions loginOptions2 = loginOptions; StartEGSLogin(loginOptions2); } private void StartEGSLogin(Epic.OnlineServices.Auth.LoginOptions loginOptions, bool attemptLink = false) { loginState = EOSLoginState.AttemptingLogin; AuthInterface authInterface = EOSPlatformManager.GetPlatformInterface().GetAuthInterface(); if (authInterface != null) { authInterface.Login(ref loginOptions, null, delegate(ref Epic.OnlineServices.Auth.LoginCallbackInfo loginCallbackInfo) { if (loginCallbackInfo.ResultCode == Result.Success) { loginState = EOSLoginState.Success; cvLinkEOSAccount.SetBool(newValue: false); ProcessSuccessfulAuthLogin(loginCallbackInfo.LocalUserId); } else if (Common.IsOperationComplete(loginCallbackInfo.ResultCode)) { if (loginCallbackInfo.ContinuanceToken != null) { if (attemptLink) { loginState = EOSLoginState.AttemptingLink; Epic.OnlineServices.Auth.LinkAccountOptions linkAccountOptions = default(Epic.OnlineServices.Auth.LinkAccountOptions); linkAccountOptions.ContinuanceToken = loginCallbackInfo.ContinuanceToken; linkAccountOptions.LinkAccountFlags = LinkAccountFlags.NoFlags; Epic.OnlineServices.Auth.LinkAccountOptions options = linkAccountOptions; authInterface.LinkAccount(ref options, null, delegate(ref Epic.OnlineServices.Auth.LinkAccountCallbackInfo linkAccountCallbackInfo) { if (linkAccountCallbackInfo.ResultCode == Result.Success) { loginState = EOSLoginState.Success; ProcessSuccessfulAuthLogin(linkAccountCallbackInfo.LocalUserId); } else { cvLinkEOSAccount.SetBool(newValue: false); loginState = EOSLoginState.FailedLink; } }); } else { ProcessSteamAppTicketConnectLogin(loginOptions.Credentials.Value.Token); } } else { loginState = EOSLoginState.FailedLogin; } } else { loginState = EOSLoginState.FailedLogin; } }); return; } loginState = EOSLoginState.FailedLogin; throw new Exception("Failed to get auth interface"); } private void ProcessSuccessfulAuthLogin(EpicAccountId loggedInId) { loggedInAuthId = loggedInId; EOSLoginManager.OnAuthLoggedIn?.Invoke(loggedInAuthId); CopyUserAuthTokenOptions options = default(CopyUserAuthTokenOptions); if (EOSPlatformManager.GetPlatformInterface().GetAuthInterface().CopyUserAuthToken(ref options, loggedInAuthId, out var outUserAuthToken) == Result.Success) { Epic.OnlineServices.Connect.LoginOptions loginOptions = default(Epic.OnlineServices.Connect.LoginOptions); loginOptions.Credentials = new Epic.OnlineServices.Connect.Credentials { Token = outUserAuthToken.Value.AccessToken, Type = ExternalCredentialType.Epic }; loginOptions.UserLoginInfo = null; Epic.OnlineServices.Connect.LoginOptions options2 = loginOptions; AttemptConnectLogin(options2); } } private void ProcessSteamAppTicketConnectLogin(string appTicket) { Epic.OnlineServices.Connect.LoginOptions loginOptions = default(Epic.OnlineServices.Connect.LoginOptions); loginOptions.Credentials = new Epic.OnlineServices.Connect.Credentials { Token = appTicket, Type = ExternalCredentialType.SteamSessionTicket }; loginOptions.UserLoginInfo = null; Epic.OnlineServices.Connect.LoginOptions options = loginOptions; AttemptConnectLogin(options); } private bool IsConnectInterfaceValid() { if (connectInterface == null) { connectInterface = EOSPlatformManager.GetPlatformInterface().GetConnectInterface(); } return connectInterface != null; } private void AttemptConnectLogin(Epic.OnlineServices.Connect.LoginOptions options) { if (IsConnectInterfaceValid()) { connectInterface.Login(ref options, null, delegate(ref Epic.OnlineServices.Connect.LoginCallbackInfo loginCallbackInfo) { if (loginCallbackInfo.ResultCode == Result.Success) { CompleteConnectLogin(loginCallbackInfo.LocalUserId); } else if (loginCallbackInfo.ResultCode == Result.InvalidUser) { CreateUserOptions createUserOptions = default(CreateUserOptions); createUserOptions.ContinuanceToken = loginCallbackInfo.ContinuanceToken; CreateUserOptions options2 = createUserOptions; connectInterface.CreateUser(ref options2, null, delegate(ref CreateUserCallbackInfo createUserCallbackInfo) { if (createUserCallbackInfo.ResultCode == Result.Success) { CompleteConnectLogin(createUserCallbackInfo.LocalUserId); } else { loginState = EOSLoginState.FailedLogin; } }); } else if (Common.IsOperationComplete(loginCallbackInfo.ResultCode)) { loginState = EOSLoginState.FailedLogin; } }); return; } throw new Exception("Failed to get connect interface"); } private void CompleteConnectLogin(ProductUserId localUserId) { loggedInProductId = localUserId; loggedInUserID = new PlatformID(loggedInProductId); EOSLoginManager.OnConnectLoggedIn?.Invoke(loggedInProductId); AddNotifyAuthExpirationOptions options = default(AddNotifyAuthExpirationOptions); connectInterface.AddNotifyAuthExpiration(ref options, null, OnAuthExpirationCallback); loginState = EOSLoginState.Success; } private void OnAuthExpirationCallback(ref AuthExpirationCallbackInfo data) { if (loggedInAuthId != null) { ProcessSuccessfulAuthLogin(loggedInAuthId); } else { UpdateSessionAuthTicket(); } } }