// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Linq;
namespace Epic.OnlineServices
{
public sealed partial class Helper
{
///
/// Adds a callback to the wrapper.
///
/// The generated client data address.
/// The client data of the callback.
/// The public delegate of the callback.
/// The private delegate of the callback.
/// Any delegates passed in with input structs.
internal static void AddCallback(out IntPtr clientDataAddress, object clientData, Delegate publicDelegate, Delegate privateDelegate, params Delegate[] structDelegates)
{
lock (s_Callbacks)
{
clientDataAddress = AddClientData(clientData);
s_Callbacks.Add(clientDataAddress, new DelegateHolder(publicDelegate, privateDelegate, structDelegates));
}
}
///
/// Removes a callback from the wrapper.
///
/// The client data address of the callback.
private static void RemoveCallback(IntPtr clientDataAddress)
{
lock (s_Callbacks)
{
s_Callbacks.Remove(clientDataAddress);
RemoveClientData(clientDataAddress);
}
}
///
/// Tries to get the callback associated with the given internal callback info, and then removes it from the wrapper if applicable.
/// Single-use callbacks will be cleaned up by this function.
///
/// The internal callback info type.
/// The callback type.
/// The callback info type.
/// The internal callback info.
/// The callback associated with the internal callback info.
/// The callback info.
/// Whether the callback was successfully retrieved.
internal static bool TryGetAndRemoveCallback(ref TCallbackInfoInternal callbackInfoInternal, out TCallback callback, out TCallbackInfo callbackInfo)
where TCallbackInfoInternal : struct, ICallbackInfoInternal, IGettable
where TCallback : class
where TCallbackInfo : struct, ICallbackInfo
{
IntPtr clientDataAddress;
Get(ref callbackInfoInternal, out callbackInfo, out clientDataAddress);
callback = null;
lock (s_Callbacks)
{
DelegateHolder delegateHolder;
if (s_Callbacks.TryGetValue(clientDataAddress, out delegateHolder))
{
callback = delegateHolder.Public as TCallback;
if (callback != null)
{
// If this delegate was added with an AddNotify, we should only ever remove it on RemoveNotify.
if (delegateHolder.NotificationId.HasValue)
{
}
// If the operation is complete, it's safe to remove.
else if (callbackInfo.GetResultCode().HasValue && Common.IsOperationComplete(callbackInfo.GetResultCode().Value))
{
RemoveCallback(clientDataAddress);
}
return true;
}
}
}
return false;
}
///
/// Tries to get the struct callback associated with the given internal callback info.
///
/// The internal callback info type.
/// The callback type.
/// The callback info type.
/// The internal callback info.
/// The callback associated with the internal callback info.
/// The callback info.
/// Whether the callback was successfully retrieved.
internal static bool TryGetStructCallback(ref TCallbackInfoInternal callbackInfoInternal, out TCallback callback, out TCallbackInfo callbackInfo)
where TCallbackInfoInternal : struct, ICallbackInfoInternal, IGettable
where TCallback : class
where TCallbackInfo : struct
{
IntPtr clientDataAddress;
Get(ref callbackInfoInternal, out callbackInfo, out clientDataAddress);
callback = null;
lock (s_Callbacks)
{
DelegateHolder delegateHolder;
if (s_Callbacks.TryGetValue(clientDataAddress, out delegateHolder))
{
callback = delegateHolder.StructDelegates.FirstOrDefault(structDelegate => structDelegate.GetType() == typeof(TCallback)) as TCallback;
if (callback != null)
{
return true;
}
}
}
return false;
}
///
/// Removes a callback from the wrapper by an associated notification id.
///
/// The notification id associated with the callback.
internal static void RemoveCallbackByNotificationId(ulong notificationId)
{
lock (s_Callbacks)
{
var clientDataAddress = s_Callbacks.SingleOrDefault(pair => pair.Value.NotificationId.HasValue && pair.Value.NotificationId == notificationId);
RemoveCallback(clientDataAddress.Key);
}
}
///
/// Adds a static callback to the wrapper.
///
/// The key of the callback.
/// The public delegate of the callback.
/// The private delegate of the callback
internal static void AddStaticCallback(string key, Delegate publicDelegate, Delegate privateDelegate)
{
lock (s_StaticCallbacks)
{
s_StaticCallbacks.Remove(key);
s_StaticCallbacks.Add(key, new DelegateHolder(publicDelegate, privateDelegate));
}
}
///
/// Tries to get the static callback associated with the given key.
///
/// The callback type.
/// The key of the callback.
/// The callback associated with the key.
/// Whether the callback was successfully retrieved.
internal static bool TryGetStaticCallback(string key, out TCallback callback)
where TCallback : class
{
callback = null;
lock (s_StaticCallbacks)
{
DelegateHolder delegateHolder;
if (s_StaticCallbacks.TryGetValue(key, out delegateHolder))
{
callback = delegateHolder.Public as TCallback;
if (callback != null)
{
return true;
}
}
}
return false;
}
///
/// Assigns a notification id to a callback by client data address associated with the callback.
///
/// The client data address associated with the callback.
/// The notification id to assign.
internal static void AssignNotificationIdToCallback(IntPtr clientDataAddress, ulong notificationId)
{
if (notificationId == 0)
{
RemoveCallback(clientDataAddress);
return;
}
lock (s_Callbacks)
{
DelegateHolder delegateHolder;
if (s_Callbacks.TryGetValue(clientDataAddress, out delegateHolder))
{
delegateHolder.NotificationId = notificationId;
}
}
}
///
/// Adds client data to the wrapper.
///
/// The client data to add.
/// The address of the added client data.
private static IntPtr AddClientData(object clientData)
{
lock (s_ClientDatas)
{
long clientDataId = ++s_LastClientDataId;
IntPtr clientDataAddress = new IntPtr(clientDataId);
s_ClientDatas.Add(clientDataAddress, clientData);
return clientDataAddress;
}
}
///
/// Removes a client data from the wrapper.
///
/// The address of the client data to remove.
private static void RemoveClientData(IntPtr clientDataAddress)
{
lock (s_ClientDatas)
{
s_ClientDatas.Remove(clientDataAddress);
}
}
///
/// Gets client data by its address.
///
/// The address of the client data.
/// Th client data associated with the address.
private static object GetClientData(IntPtr clientDataAddress)
{
lock (s_ClientDatas)
{
object clientData;
s_ClientDatas.TryGetValue(clientDataAddress, out clientData);
return clientData;
}
}
}
}