#nullable enable using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading.Tasks; using Barotrauma.Extensions; using Barotrauma.Networking; using Barotrauma.Steam; using Microsoft.Xna.Framework; namespace Barotrauma.Eos; internal static class EosAccount { /// /// The user can have several account IDs if they've linked their Steam account to an Epic Games account /// public static ImmutableHashSet SelfAccountIds { get; private set; } = ImmutableHashSet.Empty; private static readonly Queue postLoginActions = new(); private static bool isLoggedIn; public static void RefreshSelfAccountIds(Action? onRefreshComplete = null) { SelfAccountIds = ImmutableHashSet.Empty; var selfPuids = EosInterface.IdQueries.GetLoggedInPuids(); if (selfPuids.Length == 0) { onRefreshComplete?.Invoke(); return; } var collectedIds = new Option>[selfPuids.Length]; Action taskDoneHandler(int index) { void countDoneTask(Task t) { try { if (!t.TryGetResult(out Result, EosInterface.IdQueries.GetSelfExternalIdError>? result)) { return; } if (!result.TryUnwrapSuccess(out var ids)) { return; } collectedIds[index] = Option.Some(ids); } finally { // If we failed to get IDs from this query, fill in the relevant slot in the collectedIds array // to indicate that the task is done anyway collectedIds[index] = Option.Some(collectedIds[index].Fallback(ImmutableArray.Empty)); // If all of the tasks are done, merge all of the collected IDs into the hashset if (collectedIds.All(o => o.IsSome())) { SelfAccountIds = collectedIds.NotNone().SelectMany(a => a).ToImmutableHashSet(); onRefreshComplete?.Invoke(); } } } return countDoneTask; } for (int i = 0; i < selfPuids.Length; i++) { TaskPool.Add($"SelfPlayerRowWithExternalAccountIds{i}", EosInterface.IdQueries.GetSelfExternalAccountIds(selfPuids[i]), taskDoneHandler(i)); } } #region Message box stuff private static GUIMessageBox? messageBox; public static void ReplaceMessageBox(GUIMessageBox? newMessageBox) { messageBox?.Close(); messageBox = newMessageBox; } public static void CloseMessageBox() => ReplaceMessageBox(null); public static GUIMessageBox CreateLoadingMessageBox((Func CanCancel, Action Cancel)? actions = null) { var relativeSize = messageBox?.InnerFrame.RectTransform.RelativeSize ?? (0.35f, 0.3f); var newMessageBox = new GUIMessageBox( headerText: LocalizedString.EmptyString, text: LocalizedString.EmptyString, relativeSize: relativeSize, buttons: actions != null ? new[] { TextManager.Get("Cancel") } : Array.Empty()); if (actions != null) { newMessageBox.Buttons[0].Visible = false; newMessageBox.Buttons[0].OnClicked = (_, _) => { actions.Value.Cancel.Invoke(); return false; }; new GUICustomComponent(new RectTransform(Vector2.Zero, newMessageBox.InnerFrame.RectTransform), onUpdate: (_, _) => { bool canCancel = actions.Value.CanCancel.Invoke(); newMessageBox.Buttons[0].Visible |= canCancel; newMessageBox.Buttons[0].Enabled = canCancel; }); } new GUICustomComponent( new RectTransform(Vector2.One * 0.25f, newMessageBox.InnerFrame.RectTransform, Anchor.Center, scaleBasis: ScaleBasis.Smallest), onDraw: static (sb, component) => { GUIStyle.GenericThrobber.Draw( sb, spriteIndex: (int)(Timing.TotalTime * 20f) % GUIStyle.GenericThrobber.FrameCount, pos: component.Rect.Center.ToVector2(), color: Color.White, origin: GUIStyle.GenericThrobber.FrameSize.ToVector2() * 0.5f, rotate: 0f, scale: component.Rect.Size.ToVector2() / GUIStyle.GenericThrobber.FrameSize.ToVector2()); }); ReplaceMessageBox(newMessageBox); return newMessageBox; } public static Action RetryAction(LocalizedString intro, LocalizedString reason, Action retryAction, Action cancelAction) { return () => GameMain.ExecuteAfterContentFinishedLoading(() => AskRetry(intro, reason, retryAction, cancelAction)); } private static void AskRetry(LocalizedString intro, LocalizedString failureReason, Action retryAction, Action cancelAction) { var options = new[] { TextManager.Get("Retry"), TextManager.Get("Cancel") }; var askHowToProceed = TextManager.Get("AskHowToProceed"); GUIMessageBox msgBox = new GUIMessageBox( headerText: TextManager.Get("EosIntroHeader"), text: intro + "\n\n" + failureReason + "\n\n" + askHowToProceed, options, relativeSize: (0.4f, 0.4f)); msgBox.Buttons[0].OnClicked = delegate { retryAction(); CloseMessageBox(); return false; }; msgBox.Buttons[1].OnClicked = delegate { cancelAction(); CloseMessageBox(); return false; }; ReplaceMessageBox(msgBox); } #endregion public static void LoginPlatformSpecific() { if (GameMain.Instance.EgsExchangeCode.TryUnwrap(out var exchangeCode)) { LoginEpic(exchangeCode); } else if (SteamManager.IsInitialized) { LoginSteam(); } } private static void LoginSteam() => EosSteamPrimaryLogin.Start(); private static void LoginEpic(string exchangeCode) => EosEpicPrimaryLogin.Start(exchangeCode); public static void OnLoginSuccess() { isLoggedIn = true; while (postLoginActions.TryDequeue(out var action)) { action(); } } public static void ExecuteAfterLogin(Action action) { if (isLoggedIn) { action(); return; } postLoginActions.Enqueue(action); } }