v1.3.0.1 (Epic Store release)

This commit is contained in:
Regalis11
2024-03-28 18:34:33 +02:00
parent 81ca8637be
commit 3791670c42
269 changed files with 13160 additions and 2966 deletions
@@ -0,0 +1,249 @@
#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<Result<Epic.OnlineServices.UserInfo.UserInfoData, EosInterface.Friends.GetFriendsError>> 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<Epic.OnlineServices.UserInfo.QueryUserInfoCallbackInfo>();
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<Result<EosInterface.EgsFriend, EosInterface.Friends.GetFriendsError>> 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<Epic.OnlineServices.Presence.QueryPresenceCallbackInfo>();
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<Epic.OnlineServices.Presence.DataRecord>();
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<Result<EosInterface.EgsFriend, EosInterface.Friends.GetFriendsError>> 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<Result<EosInterface.EgsFriend, EosInterface.Friends.GetFriendsError>> 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<Result<ImmutableArray<EosInterface.EgsFriend>, 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<Epic.OnlineServices.Friends.QueryFriendsCallbackInfo>();
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<EosInterface.EgsFriend>();
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<Result<EosInterface.EgsFriend, EosInterface.Friends.GetFriendsError>> GetFriend(EpicAccountId selfEaid, EpicAccountId friendEaid)
=> TaskScheduler.Schedule(() => FriendsPrivate.GetFriend(selfEaid, friendEaid));
public override Task<Result<ImmutableArray<EosInterface.EgsFriend>, EosInterface.Friends.GetFriendsError>> GetFriends(EpicAccountId epicAccountId)
=> TaskScheduler.Schedule(() => FriendsPrivate.GetFriends(epicAccountId));
public override Task<Result<EosInterface.EgsFriend, EosInterface.Friends.GetFriendsError>> GetSelfUserInfo(EpicAccountId epicAccountId)
=> TaskScheduler.Schedule(() => FriendsPrivate.GetSelfUserInfo(epicAccountId));
}
@@ -0,0 +1,465 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using Barotrauma;
using Barotrauma.Extensions;
using EpicAccountId = Barotrauma.Networking.EpicAccountId;
using Result = Barotrauma.Result;
namespace EosInterfacePrivate;
static class PresencePrivate
{
internal static readonly NamedEvent<EosInterface.Presence.JoinGameInfo> OnJoinGame = new NamedEvent<EosInterface.Presence.JoinGameInfo>();
private static ulong joinGameAcceptedNotificationId = Epic.OnlineServices.Common.InvalidNotificationid;
internal static readonly NamedEvent<EosInterface.Presence.AcceptInviteInfo> OnInviteAccepted = new NamedEvent<EosInterface.Presence.AcceptInviteInfo>();
private static ulong inviteAcceptedNotificationId = Epic.OnlineServices.Common.InvalidNotificationid;
private static ulong inviteRejectedNotificationId = Epic.OnlineServices.Common.InvalidNotificationid;
internal static readonly NamedEvent<EosInterface.Presence.ReceiveInviteInfo> OnInviteReceived = new NamedEvent<EosInterface.Presence.ReceiveInviteInfo>();
private static ulong inviteReceivedNotificationId = Epic.OnlineServices.Common.InvalidNotificationid;
public static void Init(ImplementationPrivate implementation)
{
var presenceInterface = CorePrivate.EgsPresenceInterface;
var customInvitesInterface = CorePrivate.EgsCustomInvitesInterface;
if (presenceInterface is null
|| customInvitesInterface is null)
{
return;
}
var boilerplate0 = new Epic.OnlineServices.Presence.AddNotifyJoinGameAcceptedOptions();
joinGameAcceptedNotificationId = presenceInterface.AddNotifyJoinGameAccepted(ref boilerplate0, null, OnJoinGameAcceptedEos);
var boilerplate1 = new Epic.OnlineServices.CustomInvites.AddNotifyCustomInviteAcceptedOptions();
inviteAcceptedNotificationId = customInvitesInterface.AddNotifyCustomInviteAccepted(ref boilerplate1, implementation, OnInviteAcceptedEos);
var boilerplate2 = new Epic.OnlineServices.CustomInvites.AddNotifyCustomInviteRejectedOptions();
inviteRejectedNotificationId = customInvitesInterface.AddNotifyCustomInviteRejected(ref boilerplate2, null, OnInviteRejectedEos);
var boilerplate3 = new Epic.OnlineServices.CustomInvites.AddNotifyCustomInviteReceivedOptions();
inviteReceivedNotificationId = customInvitesInterface.AddNotifyCustomInviteReceived(ref boilerplate3, implementation, OnInviteReceivedEos);
}
public static void Quit()
{
OnJoinGame.Dispose();
OnInviteAccepted.Dispose();
var presenceInterface = CorePrivate.EgsPresenceInterface;
var customInvitesInterface = CorePrivate.EgsCustomInvitesInterface;
if (presenceInterface is null
|| customInvitesInterface is null)
{
return;
}
static void callRemover(Action<ulong> remover, ref ulong id)
{
remover(id);
id = Epic.OnlineServices.Common.InvalidNotificationid;
}
callRemover(presenceInterface.RemoveNotifyJoinGameAccepted, ref joinGameAcceptedNotificationId);
callRemover(customInvitesInterface.RemoveNotifyCustomInviteAccepted, ref inviteAcceptedNotificationId);
callRemover(customInvitesInterface.RemoveNotifyCustomInviteRejected, ref inviteRejectedNotificationId);
callRemover(customInvitesInterface.RemoveNotifyCustomInviteReceived, ref inviteReceivedNotificationId);
}
private static void OnJoinGameAcceptedEos(ref Epic.OnlineServices.Presence.JoinGameAcceptedCallbackInfo data)
{
if (data.UiEventId != Epic.OnlineServices.UI.UIInterface.EventidInvalid)
{
// What is this for? I have no idea.
// Documentation says it's important tho:
// https://dev.epicgames.com/docs/epic-account-services/social-overlay-overview/sdk-integration#invite-lifecycle-and-caveats
var egsUiInterface = CorePrivate.EgsUiInterface;
if (egsUiInterface != null)
{
var ack = new Epic.OnlineServices.UI.AcknowledgeEventIdOptions
{
UiEventId = data.UiEventId,
Result = Epic.OnlineServices.Result.Success
};
egsUiInterface.AcknowledgeEventId(ref ack);
}
}
var selfEpicIdOption = EpicAccountId.Parse(data.LocalUserId.ToString());
if (!selfEpicIdOption.TryUnwrap(out var selfEpicId)) { return; }
var joinCommandStr = data.JoinInfo;
OnJoinGame.Invoke(new EosInterface.Presence.JoinGameInfo(selfEpicId, joinCommandStr));
}
private static void OnInviteAcceptedEos(ref Epic.OnlineServices.CustomInvites.OnCustomInviteAcceptedCallbackInfo data)
{
if (data.LocalUserId is null) { return; }
if (data.ClientData is not ImplementationPrivate implementation) { return; }
RemoveInvite(
recipientPuid: new EosInterface.ProductUserId(data.LocalUserId.ToString()),
senderPuid: new EosInterface.ProductUserId(data.TargetUserId.ToString()));
var joinCommandStr = data.Payload;
var selfPuid = new EosInterface.ProductUserId(data.LocalUserId.ToString());
async Task<Option<EosInterface.Presence.AcceptInviteInfo>> prepareCallbackInfo()
{
var selfExternalAccountIdsTask = IdQueriesPrivate.GetExternalAccountIds(selfPuid, selfPuid);
await Task.WhenAll(selfExternalAccountIdsTask, selfExternalAccountIdsTask);
var selfExternalAccountIdsResult = await selfExternalAccountIdsTask;
if (!selfExternalAccountIdsResult.TryUnwrapSuccess(out var selfExternalAccountIds)
|| !selfExternalAccountIds.OfType<EpicAccountId>().FirstOrNone().TryUnwrap(out var selfEpicAccountId))
{
return Option.None;
}
return Option.Some(new EosInterface.Presence.AcceptInviteInfo(
selfEpicAccountId,
joinCommandStr));
}
TaskPool.Add(
$"AcceptedInviteFor{selfPuid.Value}",
implementation.TaskScheduler.Schedule(prepareCallbackInfo),
t =>
{
if (!t.TryGetResult(out Option<EosInterface.Presence.AcceptInviteInfo> infoOption)) { return; }
if (!infoOption.TryUnwrap(out var info)) { return; }
OnInviteAccepted.Invoke(info);
});
}
private static void OnInviteRejectedEos(ref Epic.OnlineServices.CustomInvites.CustomInviteRejectedCallbackInfo data)
{
if (data.LocalUserId is null) { return; }
RemoveInvite(
recipientPuid: new EosInterface.ProductUserId(data.LocalUserId.ToString()),
senderPuid: new EosInterface.ProductUserId(data.TargetUserId.ToString()));
}
private readonly record struct InviteId(
EpicAccountId RecipientEpicId,
EpicAccountId SenderEpicId,
EosInterface.ProductUserId RecipientPuid,
EosInterface.ProductUserId SenderPuid,
string IdValue);
private static readonly List<InviteId> ReceivedInviteIds = new List<InviteId>();
private static void RemoveInvite(EpicAccountId recipientEpicId, EpicAccountId senderEpicId)
{
RemoveInvites(ReceivedInviteIds.Where(id => id.RecipientEpicId == recipientEpicId && id.SenderEpicId == senderEpicId).ToImmutableArray());
}
private static void RemoveInvite(EosInterface.ProductUserId recipientPuid, EosInterface.ProductUserId senderPuid)
{
RemoveInvites(ReceivedInviteIds.Where(id => id.RecipientPuid == recipientPuid && id.SenderPuid == senderPuid).ToImmutableArray());
}
private static void RemoveInvites(ImmutableArray<InviteId> invites)
{
var customInvitesInterface = CorePrivate.EgsCustomInvitesInterface;
if (customInvitesInterface == null) { return; }
foreach (var invite in invites)
{
ReceivedInviteIds.Remove(invite);
var targetUserId = Epic.OnlineServices.ProductUserId.FromString(invite.SenderPuid.Value);
var localUserId = Epic.OnlineServices.ProductUserId.FromString(invite.RecipientPuid.Value);
var finalizeInviteOptions = new Epic.OnlineServices.CustomInvites.FinalizeInviteOptions
{
TargetUserId = targetUserId,
LocalUserId = localUserId,
CustomInviteId = invite.IdValue,
ProcessingResult = Epic.OnlineServices.Result.Success
};
customInvitesInterface.FinalizeInvite(ref finalizeInviteOptions);
}
}
private static void OnInviteReceivedEos(ref Epic.OnlineServices.CustomInvites.OnCustomInviteReceivedCallbackInfo data)
{
if (data.ClientData is not ImplementationPrivate implementation) { return; }
var joinCommandStr = data.Payload;
var selfPuid = new EosInterface.ProductUserId(data.LocalUserId.ToString());
var senderPuid = new EosInterface.ProductUserId(data.TargetUserId.ToString());
var inviteIdValue = data.CustomInviteId;
// We can only have one invite for the same recipient-sender pair
RemoveInvite(
recipientPuid: selfPuid,
senderPuid: senderPuid);
async Task<Option<EosInterface.Presence.ReceiveInviteInfo>> prepareCallbackInfo()
{
var selfExternalAccountIdsTask = IdQueriesPrivate.GetExternalAccountIds(selfPuid, selfPuid);
var senderExternalAccountIdsTask = IdQueriesPrivate.GetExternalAccountIds(selfPuid, senderPuid);
await Task.WhenAll(selfExternalAccountIdsTask, selfExternalAccountIdsTask);
var selfExternalAccountIdsResult = await selfExternalAccountIdsTask;
var senderExternalAccountIdsResult = await senderExternalAccountIdsTask;
if (!selfExternalAccountIdsResult.TryUnwrapSuccess(out var selfExternalAccountIds)
|| !selfExternalAccountIds.OfType<EpicAccountId>().FirstOrNone().TryUnwrap(out var selfEpicAccountId))
{
return Option.None;
}
if (!senderExternalAccountIdsResult.TryUnwrapSuccess(out var senderExternalAccountIds)
|| !senderExternalAccountIds.OfType<EpicAccountId>().FirstOrNone().TryUnwrap(out var senderEpicAccountId))
{
return Option.None;
}
return Option.Some(new EosInterface.Presence.ReceiveInviteInfo(
selfEpicAccountId,
senderEpicAccountId,
joinCommandStr));
}
TaskPool.Add(
$"ReceivedInviteFrom{senderPuid.Value}",
implementation.TaskScheduler.Schedule(prepareCallbackInfo),
t =>
{
if (!t.TryGetResult(out Option<EosInterface.Presence.ReceiveInviteInfo> infoOption)) { return; }
if (!infoOption.TryUnwrap(out var info)) { return; }
ReceivedInviteIds.Add(new InviteId(
RecipientEpicId: info.RecipientId,
SenderEpicId: info.SenderId,
RecipientPuid: selfPuid,
SenderPuid: senderPuid,
IdValue: inviteIdValue));
OnInviteReceived.Invoke(info);
});
}
public static async Task<Result<Unit, EosInterface.Presence.SetJoinCommandError>> SetJoinCommand(
EpicAccountId epicAccountId,
string desc,
string serverName,
string joinCommand)
{
if (string.IsNullOrWhiteSpace(joinCommand))
{
desc = "";
}
if (desc.Length > Epic.OnlineServices.Presence.PresenceInterface.RichTextMaxValueLength)
{
return Result.Failure(EosInterface.Presence.SetJoinCommandError.DescTooLong);
}
if (joinCommand.Length > Epic.OnlineServices.Presence.PresenceModification.PresencemodificationJoininfoMaxLength)
{
return Result.Failure(EosInterface.Presence.SetJoinCommandError.JoinCommandTooLong);
}
if (serverName.Length > Epic.OnlineServices.Presence.PresenceInterface.DataMaxValueLength)
{
return Result.Failure(EosInterface.Presence.SetJoinCommandError.ServerNameTooLong);
}
if (joinCommand.Length > Epic.OnlineServices.Presence.PresenceInterface.DataMaxValueLength)
{
return Result.Failure(EosInterface.Presence.SetJoinCommandError.JoinCommandTooLong);
}
using var janitor = Janitor.Start();
var presenceInterface = CorePrivate.EgsPresenceInterface;
var customInvitesInterface = CorePrivate.EgsCustomInvitesInterface;
if (presenceInterface is null
|| customInvitesInterface is null)
{
return Result.Failure(EosInterface.Presence.SetJoinCommandError.EosNotInitialized);
}
var epicAccountIdInternal = Epic.OnlineServices.EpicAccountId.FromString(epicAccountId.EosStringRepresentation);
var puidResult = await IdQueriesPrivate.GetPuidForExternalId(epicAccountId);
if (!puidResult.TryUnwrapSuccess(out var puid))
{
return Result.Failure(EosInterface.Presence.SetJoinCommandError.FailedToGetPuid);
}
var puidInternal = Epic.OnlineServices.ProductUserId.FromString(puid.Value);
var setCustomInviteOptions = new Epic.OnlineServices.CustomInvites.SetCustomInviteOptions
{
LocalUserId = puidInternal,
Payload = joinCommand
};
var setCustomInviteResult = customInvitesInterface.SetCustomInvite(ref setCustomInviteOptions);
if (setCustomInviteResult != Epic.OnlineServices.Result.Success)
{
return Result.Failure(EosInterface.Presence.SetJoinCommandError.FailedToSetCustomInvite);
}
var createPresenceModificationOptions = new Epic.OnlineServices.Presence.CreatePresenceModificationOptions
{
LocalUserId = epicAccountIdInternal
};
var createPresenceModificationResult = presenceInterface.CreatePresenceModification(ref createPresenceModificationOptions, out var presenceModification);
janitor.AddAction(presenceModification.Release);
if (createPresenceModificationResult != Epic.OnlineServices.Result.Success)
{
return Result.Failure(EosInterface.Presence.SetJoinCommandError.FailedToCreatePresenceModification);
}
var setRichTextOptions = new Epic.OnlineServices.Presence.PresenceModificationSetRawRichTextOptions
{
RichText = desc
};
var setRichTextResult = presenceModification.SetRawRichText(ref setRichTextOptions);
if (setRichTextResult != Epic.OnlineServices.Result.Success)
{
return Result.Failure(EosInterface.Presence.SetJoinCommandError.FailedToSetRichText);
}
var setDataOptions = new Epic.OnlineServices.Presence.PresenceModificationSetDataOptions
{
Records = new[]
{
new Epic.OnlineServices.Presence.DataRecord
{
Key = "servername",
Value = serverName
},
new Epic.OnlineServices.Presence.DataRecord
{
Key = "connectcommand",
Value = joinCommand
}
}
};
var setDataResult = presenceModification.SetData(ref setDataOptions);
if (setDataResult != Epic.OnlineServices.Result.Success)
{
return Result.Failure(EosInterface.Presence.SetJoinCommandError.FailedToSetRecords);
}
// This is necessary to make the SDK not choke if given an empty, but not null, joinCommand
string? joinCommandNullable = string.IsNullOrWhiteSpace(joinCommand) ? null : joinCommand;
var setJoinInfoOptions = new Epic.OnlineServices.Presence.PresenceModificationSetJoinInfoOptions
{
JoinInfo = joinCommandNullable
};
var setJoinInfoResult = presenceModification.SetJoinInfo(ref setJoinInfoOptions);
if (setJoinInfoResult != Epic.OnlineServices.Result.Success)
{
return Result.Failure(EosInterface.Presence.SetJoinCommandError.FailedToSetJoinInfo);
}
var setPresenceOptions = new Epic.OnlineServices.Presence.SetPresenceOptions
{
LocalUserId = epicAccountIdInternal,
PresenceModificationHandle = presenceModification
};
var setPresenceWaiter = new CallbackWaiter<Epic.OnlineServices.Presence.SetPresenceCallbackInfo>();
presenceInterface.SetPresence(options: ref setPresenceOptions, clientData: null, completionDelegate: setPresenceWaiter.OnCompletion);
var setPresenceResultOption = await setPresenceWaiter.Task;
if (!setPresenceResultOption.TryUnwrap(out var setPresenceResult))
{
return Result.Failure(EosInterface.Presence.SetJoinCommandError.SetPresenceTimedOut);
}
if (setPresenceResult.ResultCode != Epic.OnlineServices.Result.Success)
{
return Result.Failure(EosInterface.Presence.SetJoinCommandError.FailedToSetPresence);
}
return Result.Success(Unit.Value);
}
public static async Task<Result<Unit, EosInterface.Presence.SendInviteError>> SendInvite(EpicAccountId selfEpicAccountId, EpicAccountId remoteEpicAccountId)
{
var customInvitesInterface = CorePrivate.EgsCustomInvitesInterface;
if (customInvitesInterface is null)
{
return Result.Failure(EosInterface.Presence.SendInviteError.EosNotInitialized);
}
var selfPuidResult = await IdQueriesPrivate.GetPuidForExternalId(selfEpicAccountId);
if (!selfPuidResult.TryUnwrapSuccess(out var selfPuid))
{
return Result.Failure(EosInterface.Presence.SendInviteError.FailedToGetSelfPuid);
}
var selfPuidInternal = Epic.OnlineServices.ProductUserId.FromString(selfPuid.Value);
var remotePuidResult = await IdQueriesPrivate.GetPuidForExternalId(remoteEpicAccountId);
if (!remotePuidResult.TryUnwrapSuccess(out var remotePuid))
{
return Result.Failure(EosInterface.Presence.SendInviteError.FailedToGetRemotePuid);
}
var remotePuidInternal = Epic.OnlineServices.ProductUserId.FromString(remotePuid.Value);
var sendCustomInviteOptions = new Epic.OnlineServices.CustomInvites.SendCustomInviteOptions
{
LocalUserId = selfPuidInternal,
TargetUserIds = new[]
{
remotePuidInternal
}
};
var callbackWaiter = new CallbackWaiter<Epic.OnlineServices.CustomInvites.SendCustomInviteCallbackInfo>();
customInvitesInterface.SendCustomInvite(options: ref sendCustomInviteOptions, clientData: null, completionDelegate: callbackWaiter.OnCompletion);
var callbackResultOption = await callbackWaiter.Task;
if (!callbackResultOption.TryUnwrap(out var callbackResult))
{
return Result.Failure(EosInterface.Presence.SendInviteError.TimedOut);
}
if (callbackResult.ResultCode != Epic.OnlineServices.Result.Success)
{
return Result.Failure(EosInterface.Presence.SendInviteError.InternalError);
}
return Result.Success(Unit.Value);
}
public static void DeclineInvite(EpicAccountId selfEpicAccountId, EpicAccountId senderEpicAccountId)
{
RemoveInvite(
recipientEpicId: selfEpicAccountId,
senderEpicId: senderEpicAccountId);
}
}
internal sealed partial class ImplementationPrivate : EosInterface.Implementation
{
public override NamedEvent<EosInterface.Presence.JoinGameInfo> OnJoinGame => PresencePrivate.OnJoinGame;
public override NamedEvent<EosInterface.Presence.AcceptInviteInfo> OnInviteAccepted => PresencePrivate.OnInviteAccepted;
public override NamedEvent<EosInterface.Presence.ReceiveInviteInfo> OnInviteReceived => PresencePrivate.OnInviteReceived;
public override Task<Result<Unit, EosInterface.Presence.SetJoinCommandError>> SetJoinCommand(
EpicAccountId epicAccountId, string desc, string serverName, string joinCommand)
=> TaskScheduler.Schedule(() => PresencePrivate.SetJoinCommand(epicAccountId, desc, serverName, joinCommand));
public override Task<Result<Unit, EosInterface.Presence.SendInviteError>> SendInvite(
EpicAccountId selfEpicAccountId, EpicAccountId remoteEpicAccountId)
=> TaskScheduler.Schedule(() => PresencePrivate.SendInvite(selfEpicAccountId, remoteEpicAccountId));
public override void DeclineInvite(EpicAccountId selfEpicAccountId, EpicAccountId senderEpicAccountId)
=> PresencePrivate.DeclineInvite(selfEpicAccountId, senderEpicAccountId);
}