#nullable enable using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Threading.Tasks; using Barotrauma.Networking; using Barotrauma; using Barotrauma.Extensions; namespace EosInterfacePrivate; static class FriendsPrivate { internal static async Task> GetUserInfoData( EpicAccountId selfEaid, EpicAccountId friendEaid) { if (CorePrivate.EgsUserInfoInterface is not { } egsUserInfoInterface) { return Result.Failure(EosInterface.Friends.GetFriendsError.EosNotInitialized); } var selfEaidInternal = Epic.OnlineServices.EpicAccountId.FromString(selfEaid.EosStringRepresentation); var friendEaidInternal = Epic.OnlineServices.EpicAccountId.FromString(friendEaid.EosStringRepresentation); var queryUserInfoOptions = new Epic.OnlineServices.UserInfo.QueryUserInfoOptions { LocalUserId = selfEaidInternal, TargetUserId = friendEaidInternal }; var queryUserInfoWaiter = new CallbackWaiter(); egsUserInfoInterface.QueryUserInfo(options: ref queryUserInfoOptions, clientData: null, completionDelegate: queryUserInfoWaiter.OnCompletion); var queryUserInfoResult = await queryUserInfoWaiter.Task; if (!queryUserInfoResult.TryUnwrap(out var queryUserInfo)) { return Result.Failure(EosInterface.Friends.GetFriendsError.UserInfoQueryTimedOut); } if (queryUserInfo.ResultCode != Epic.OnlineServices.Result.Success) { return Result.Failure(EosInterface.Friends.GetFriendsError.UserInfoQueryFailed); } var copyUserInfoOptions = new Epic.OnlineServices.UserInfo.CopyUserInfoOptions { LocalUserId = selfEaidInternal, TargetUserId = friendEaidInternal }; var copyUserInfoResult = egsUserInfoInterface.CopyUserInfo(ref copyUserInfoOptions, out var friendInfoNullable); if (copyUserInfoResult != Epic.OnlineServices.Result.Success) { return Result.Failure(EosInterface.Friends.GetFriendsError.CopyUserInfoFailed); } if (friendInfoNullable is not { } friendInfo) { return Result.Failure(EosInterface.Friends.GetFriendsError.CopyUserInfoFailed); } string displayName = friendInfo.Nickname ?? friendInfo.DisplayName ?? ""; if (string.IsNullOrEmpty(displayName)) { return Result.Failure(EosInterface.Friends.GetFriendsError.DisplayNameIsEmpty); } return Result.Success(friendInfo); } internal static async Task> GetPresenceFromUserInfoData( EpicAccountId selfEaid, EpicAccountId friendEaid, Epic.OnlineServices.UserInfo.UserInfoData friendInfo) { if (CorePrivate.EgsPresenceInterface is not { } egsPresenceInterface) { return Result.Failure(EosInterface.Friends.GetFriendsError.EosNotInitialized); } var selfEaidInternal = Epic.OnlineServices.EpicAccountId.FromString(selfEaid.EosStringRepresentation); var friendEaidInternal = friendInfo.UserId; string displayName = friendInfo.Nickname ?? friendInfo.DisplayName ?? ""; var queryPresenceOptions = new Epic.OnlineServices.Presence.QueryPresenceOptions { LocalUserId = selfEaidInternal, TargetUserId = friendEaidInternal }; var queryPresenceWaiter = new CallbackWaiter(); egsPresenceInterface.QueryPresence(options: ref queryPresenceOptions, clientData: null, completionDelegate: queryPresenceWaiter.OnCompletion); var queryPresenceResult = await queryPresenceWaiter.Task; if (!queryPresenceResult.TryUnwrap(out var queryPresence)) { return Result.Failure(EosInterface.Friends.GetFriendsError.EgsPresenceQueryTimedOut); } if (queryPresence.ResultCode != Epic.OnlineServices.Result.Success) { return Result.Failure(EosInterface.Friends.GetFriendsError.EgsPresenceQueryFailed); } var copyPresenceOptions = new Epic.OnlineServices.Presence.CopyPresenceOptions { LocalUserId = selfEaidInternal, TargetUserId = friendEaidInternal }; var copyPresenceResult = egsPresenceInterface.CopyPresence(ref copyPresenceOptions, out var friendPresenceNullable); if (copyPresenceResult != Epic.OnlineServices.Result.Success) { return Result.Failure(EosInterface.Friends.GetFriendsError.CopyPresenceFailed); } if (friendPresenceNullable is not { } friendPresence) { return Result.Failure(EosInterface.Friends.GetFriendsError.CopyPresenceFailed); } string productId = friendPresence.ProductId ?? ""; var friendStatus = friendPresence.Status switch { Epic.OnlineServices.Presence.Status.Offline => FriendStatus.Offline, _ => productId == PlatformInterfaceOptionsPrivate.BasePlatformInterfaceOptions.ProductId ? FriendStatus.PlayingBarotrauma : !string.IsNullOrEmpty(productId) ? FriendStatus.PlayingAnotherGame : FriendStatus.NotPlaying }; var records = friendPresence.Records ?? Array.Empty(); string getRecordValue(string key) => records .FirstOrNone(r => string.Equals(r.Key, key, StringComparison.OrdinalIgnoreCase)) .Select(r => r.Value) .Fallback(""); var connectCommand = getRecordValue("connectcommand"); var serverName = getRecordValue("servername"); return Result.Success(new EosInterface.EgsFriend( DisplayName: displayName, EpicAccountId: friendEaid, Status: friendStatus, ConnectCommand: connectCommand, ServerName: serverName)); } public static async Task> GetSelfUserInfo(EpicAccountId epicAccount) { var getUserInfoDataResult = await GetUserInfoData(epicAccount, epicAccount); if (getUserInfoDataResult.TryUnwrapFailure(out var error)) { return Result.Failure(error); } if (!getUserInfoDataResult.TryUnwrapSuccess(out var friendInfo)) { throw new UnreachableCodeException(); } string displayName = friendInfo.Nickname ?? friendInfo.DisplayName ?? ""; return Result.Success(new EosInterface.EgsFriend( DisplayName: displayName, EpicAccountId: epicAccount, Status: FriendStatus.PlayingBarotrauma, ConnectCommand: "", ServerName: "")); } public static async Task> GetFriend(EpicAccountId selfEaid, EpicAccountId friendEaid) { var getUserInfoDataResult = await GetUserInfoData(selfEaid, friendEaid); if (getUserInfoDataResult.TryUnwrapFailure(out var error)) { return Result.Failure(error); } if (!getUserInfoDataResult.TryUnwrapSuccess(out var friendInfo)) { throw new UnreachableCodeException(); } return await GetPresenceFromUserInfoData(selfEaid, friendEaid, friendInfo); } public static async Task, EosInterface.Friends.GetFriendsError>> GetFriends(EpicAccountId epicAccount) { if (CorePrivate.EgsFriendsInterface is not { } egsFriendsInterface) { return Result.Failure(EosInterface.Friends.GetFriendsError.EosNotInitialized); } var selfEaidInternal = Epic.OnlineServices.EpicAccountId.FromString(epicAccount.EosStringRepresentation); var queryFriendsOptions = new Epic.OnlineServices.Friends.QueryFriendsOptions { LocalUserId = selfEaidInternal }; var queryFriendsWaiter = new CallbackWaiter(); egsFriendsInterface.QueryFriends(options: ref queryFriendsOptions, clientData: null, completionDelegate: queryFriendsWaiter.OnCompletion); var queryFriendsInfoResult = await queryFriendsWaiter.Task; if (!queryFriendsInfoResult.TryUnwrap(out var queryFriendsInfo)) { return Result.Failure(EosInterface.Friends.GetFriendsError.EgsFriendsQueryTimedOut); } if (queryFriendsInfo.ResultCode != Epic.OnlineServices.Result.Success) { return Result.Failure(EosInterface.Friends.GetFriendsError.EgsFriendsQueryFailed); } var getFriendsCountOptions = new Epic.OnlineServices.Friends.GetFriendsCountOptions { LocalUserId = selfEaidInternal }; var friendCount = egsFriendsInterface.GetFriendsCount(ref getFriendsCountOptions); var friends = new List(); for (int i = 0; i < friendCount; i++) { var getFriendAtIndexOptions = new Epic.OnlineServices.Friends.GetFriendAtIndexOptions { LocalUserId = selfEaidInternal, Index = i }; var friendId = egsFriendsInterface.GetFriendAtIndex(ref getFriendAtIndexOptions); if (friendId == null) { continue; } if (!EpicAccountId.Parse(friendId.ToString()).TryUnwrap(out var friendIdPublic)) { continue; } var getUserInfoDataResult = await GetUserInfoData(epicAccount, friendIdPublic); if (!getUserInfoDataResult.TryUnwrapSuccess(out var friendInfo)) { continue; } var egsFriendPublicResult = await GetPresenceFromUserInfoData(epicAccount, friendIdPublic, friendInfo); if (!egsFriendPublicResult.TryUnwrapSuccess(out var egsFriendPublic)) { continue; } friends.Add(egsFriendPublic); } return Result.Success(friends.ToImmutableArray()); } } internal sealed partial class ImplementationPrivate : EosInterface.Implementation { public override Task> GetFriend(EpicAccountId selfEaid, EpicAccountId friendEaid) => TaskScheduler.Schedule(() => FriendsPrivate.GetFriend(selfEaid, friendEaid)); public override Task, EosInterface.Friends.GetFriendsError>> GetFriends(EpicAccountId epicAccountId) => TaskScheduler.Schedule(() => FriendsPrivate.GetFriends(epicAccountId)); public override Task> GetSelfUserInfo(EpicAccountId epicAccountId) => TaskScheduler.Schedule(() => FriendsPrivate.GetSelfUserInfo(epicAccountId)); }