using System; namespace CS.Platform.Playfab { public class PartyMessageEvent { public bool used; public PartyCSharpSDK.PARTY_NETWORK_DESCRIPTOR networkDescription; public PartyCSharpSDK.PARTY_ENDPOINT_MESSAGE_RECEIVED_STATE_CHANGE eventData; public string senderEntity; public Systems.User.UserInfo senderInfo; public int messageStart; public bool triggerMain; public byte[] dataRaw; } public class PartyManager { public const byte NETWORK_MESSAGE = 1; public const byte NETWORK_UPDATE_MESSAGE = 2; public const byte GAME_MESSAGE = 3; object _locker = new object(); public object Locker { get { return (_locker); } } object _messageLocker = new object(); public object MessageLocker { get { return (_messageLocker); } } string _titleID = null; PartyCSharpSDK.PARTY_HANDLE _partyHandle = null; public PartyCSharpSDK.PARTY_HANDLE PartyHandle { get { return (_partyHandle); } } PartyCSharpSDK.PARTY_LOCAL_USER_HANDLE _localUserHandle = null; public PartyCSharpSDK.PARTY_LOCAL_USER_HANDLE UserHandle { get { return (_localUserHandle); } } System.Action OnUserCreated = null; PartyMessageEvent _messageEvent = new PartyMessageEvent(); public struct LocalUser { public PlayFab.AuthenticationModels.EntityKey key; public string token; } LocalUser _localEntity = new LocalUser(); public LocalUser UserEntity { get { return (_localEntity); } } private System.IntPtr _sendBuffer; private System.IntPtr _sendMetaStart; private System.IntPtr _sendMessageStart; private byte[] _sendBufferTag = new byte[1]; private int[] _sendBufferChannel = new int[1]; private uint _sendBufferSize; private byte[] _readMessageBuffer = null; private PartyCSharpSDK.PARTY_SEND_MESSAGE_QUEUING_CONFIGURATION _sendQueuingConfiguration = null; PartyCSharpSDK.PARTY_ENDPOINT_HANDLE[] _sendTarget = new PartyCSharpSDK.PARTY_ENDPOINT_HANDLE[1]; public PartyManager(string title, uint messageBufferSize = 2048) { _titleID = title; _sendQueuingConfiguration = new PartyCSharpSDK.PARTY_SEND_MESSAGE_QUEUING_CONFIGURATION(); _sendQueuingConfiguration.Priority = Convert.ToSByte(PartyCSharpSDK.PartyConstants.c_defaultSendMessageQueuingPriority); _sendQueuingConfiguration.IdentityForCancelFilters = 0; _sendQueuingConfiguration.TimeoutInMilliseconds = 0; SetupSendBuffer(messageBufferSize); _readMessageBuffer = new byte[_sendBufferSize]; } ~PartyManager() { CleanUp(); } public bool SetupNetwork(System.Action QueueFail = null) { lock (_locker) { uint result = 0; if (_partyHandle==null) { Utils.Debug.LogInfo("[PLAYFAB:PARTYMANAGER] SetupNetwork: PartyInitialize | Title: {0}", _titleID); result = PartyCSharpSDK.SDK.PartyInitialize(_titleID, out _partyHandle); if (PartyCSharpSDK.PartyError.FAILED(result)) Utils.Debug.LogErro("[PLAYFAB:PARTYMANAGER] SetupNetwork: PartyInitialize | Result: {0} | Title: {1}", result, _titleID); else Utils.Debug.LogInfo("[PLAYFAB:PARTYMANAGER] SetupNetwork: PartyInitialize Complete | Result: {0} | Party: {1}", result, _partyHandle); CS.Platform.Core.AddMainThreadUpdate(UpdateParty); } if (_localUserHandle == null) { var temp = new PlayFab.AuthenticationModels.GetEntityTokenRequest(); Utils.Debug.LogInfo("[PLAYFAB:PARTYMANAGER] SetupNetwork: GetEntityToken"); PlayFab.PlayFabAuthenticationAPI.GetEntityToken(temp, OnEntityReturned, OnEntityError); OnUserCreated += QueueFail; } return (_localUserHandle != null); } } public void CleanUp() { lock (_locker) { CS.Platform.Core.RemoveMainThreadUpdate(UpdateParty); if (_partyHandle != null) { uint result = PartyCSharpSDK.SDK.PartyCleanup(_partyHandle); if (PartyCSharpSDK.PartyError.FAILED(result)) Utils.Debug.LogErro("[PLAYFAB:PARTYMANAGER] PartyManager: PartyCleanup | Result: {0}", result); else Utils.Debug.LogInfo("[PLAYFAB:PARTYMANAGER] PartyManager: PartyCleanup Complete | Result: {0}", result); _partyHandle = null; _localUserHandle = null; } } } private void OnEntityError(PlayFab.PlayFabError obj) { PlayfabErrorLog.LogErro("[PLAYFAB:PARTYMANAGER] OnEntityError: Failed GetEntityToken", obj); } private void OnEntityReturned(PlayFab.AuthenticationModels.GetEntityTokenResponse obj) { lock (_locker) { _localEntity.token = obj.EntityToken; _localEntity.key = obj.Entity; Utils.Debug.LogInfo("[PLAYFAB:PARTYMANAGER] OnEntityReturned: PartyCreateLocalUser | Key: {0} | Entity: {1}", _localEntity.key, _localEntity.token); uint result = PartyCSharpSDK.SDK.PartyCreateLocalUser( _partyHandle, _localEntity.key.Id, _localEntity.token, out _localUserHandle); if (PartyCSharpSDK.PartyError.FAILED(result)) Utils.Debug.LogErro("[PLAYFAB:PARTYMANAGER] OnEntityReturned: PartyCreateLocalUser Failed | Result: {0} | Key: {1} | Entity: {2}", result, _localEntity.key, _localEntity.token); else { Utils.Debug.LogInfo("[PLAYFAB:PARTYMANAGER] OnEntityReturned: PartyCreateLocalUser Complete | Result: {0} | UserHandle: {1}", result, _localUserHandle); OnUserCreated?.Invoke(); } } } interface IEventCarrier { void Trigger(PartyCSharpSDK.PARTY_STATE_CHANGE temp); } class EventLogic: IEventCarrier where T : PartyCSharpSDK.PARTY_STATE_CHANGE { private PartyCSharpSDK.PARTY_STATE_CHANGE_TYPE _type; public System.Action action; public EventLogic(PartyCSharpSDK.PARTY_STATE_CHANGE_TYPE type) { _type = type; action = null; } public void Trigger(PartyCSharpSDK.PARTY_STATE_CHANGE raw) { T data = (raw as T); if (data != null) { Utils.Debug.LogInfo("[PLAYFAB:PARTYMANAGER] EventLogic.Trigger: Trigger event | Type: {0} | DataType: {1} | Wanted: {2}", _type, raw.GetType(), typeof(T)); action?.Invoke(data); } else Utils.Debug.LogErro("[PLAYFAB:PARTYMANAGER] EventLogic.Trigger: Failed convert | Type: {0} | DataType: {1} | Wanted: {2}", _type, raw.GetType(), typeof(T)); } } private System.Collections.Generic.Dictionary _onEventCache = new System.Collections.Generic.Dictionary(); public void RegisterPartyEvent(PartyCSharpSDK.PARTY_STATE_CHANGE_TYPE type, System.Action action) where T : PartyCSharpSDK.PARTY_STATE_CHANGE { lock (_locker) { EventLogic tracker = null; if (!_onEventCache.ContainsKey(type)) { Utils.Debug.Log(Utils.Debug.Level.INFO | Utils.Debug.Level.DEEP, "[PLAYFAB:PARTYMANAGER] RegisterPartyEvent: Create new | Type: {0} | Data: {1}", type, typeof(T)); tracker = new EventLogic(type); _onEventCache.Add(type, tracker); } else tracker = (_onEventCache[type] as EventLogic); Utils.Debug.Log(Utils.Debug.Level.INFO | Utils.Debug.Level.DEEP, "[PLAYFAB:PARTYMANAGER] RegisterPartyEvent: Adding | Type: {0} | Data: {1}", type, typeof(T)); tracker.action += action; } } public void UnregisterPartyEvent(PartyCSharpSDK.PARTY_STATE_CHANGE_TYPE type, System.Action action) where T : PartyCSharpSDK.PARTY_STATE_CHANGE { lock (_locker) { if (!_onEventCache.ContainsKey(type)) Utils.Debug.LogWarn("[PLAYFAB:PARTYMANAGER] RegisterPartyEvent: Not found | Type: {0} | Data: {1}", type, typeof(T)); else { Utils.Debug.Log(Utils.Debug.Level.INFO | Utils.Debug.Level.DEEP, "[PLAYFAB:PARTYMANAGER] RegisterPartyEvent: Removing | Type: {0} | Data: {1}", type, typeof(T)); EventLogic tracker = (_onEventCache[type] as EventLogic); tracker.action -= action; } } } public void ClearEventCache() { lock (_locker) { Utils.Debug.LogWarn("[PLAYFAB:PARTYMANAGER] ClearEventCache: Clearing | Count: {0}", _onEventCache.Count); _onEventCache.Clear(); } } private System.Action _messageCheckAction = null; public void RegisterMessageCheckEvent(System.Action action) { lock (_locker) { Utils.Debug.Log(Utils.Debug.Level.INFO | Utils.Debug.Level.DEEP, "[PLAYFAB:PARTYMANAGER] RegisterMessageCheckEvent: New message event"); _messageCheckAction += action; } } public void UnregisterMessageCheckEvent(System.Action action) { lock (_locker) { Utils.Debug.Log(Utils.Debug.Level.INFO | Utils.Debug.Level.DEEP, "[PLAYFAB:PARTYMANAGER] UnregisterMessageCheckEvent: Remove message event"); _messageCheckAction -= action; } } private System.Action _messageAction = null; public void RegisterMessageEvent(System.Action action) { lock (_locker) { Utils.Debug.Log(Utils.Debug.Level.INFO | Utils.Debug.Level.DEEP, "[PLAYFAB:PARTYMANAGER] RegisterMessageEvent: New message event"); _messageAction += action; } } public void UnregisterMessageEvent(System.Action action) { lock (_locker) { Utils.Debug.Log(Utils.Debug.Level.INFO | Utils.Debug.Level.DEEP, "[PLAYFAB:PARTYMANAGER] UnregisterMessageEvent: Remove message event"); _messageAction -= action; } } void SetupSendBuffer(uint messageBufferSize) { lock (_messageLocker) { _sendBufferSize = messageBufferSize; if (_sendBufferSize <= 0) _sendBufferSize = 2048; if (_sendBuffer!=null) System.Runtime.InteropServices.Marshal.FreeHGlobal(_sendBuffer); _sendBuffer = System.Runtime.InteropServices.Marshal.AllocHGlobal((int)_sendBufferSize); _sendMetaStart = new IntPtr(_sendBuffer.ToInt64() + 1); _sendMessageStart = new IntPtr(_sendMetaStart.ToInt64() + sizeof(int)); } } public uint SendMetaMessage(PartyCSharpSDK.PARTY_ENDPOINT_HANDLE sendPoint, PartyCSharpSDK.PARTY_ENDPOINT_HANDLE sendTarget, byte tag, byte[] data, int size, bool reliable) { if (sendPoint == null) return (Utils.ErrorCode.INVALID_INPUT); if (sendTarget == null) return (Utils.ErrorCode.INVALID_INPUT); lock (_messageLocker) { if (_sendBufferSize < (size + 1)) { Utils.Debug.LogWarn("[PLAYFAB:NETWORK] SendMessage: Need to increase send buffer | Current: {0} | Needs: {1}", _sendBufferSize, (size + 1)); SetupSendBuffer((uint)(size + 1)); } _sendBufferTag[0] = tag; System.Runtime.InteropServices.Marshal.Copy(_sendBufferTag, 0, _sendBuffer, 1); if(0 < size) System.Runtime.InteropServices.Marshal.Copy(data, 0, _sendMetaStart, size); PartyCSharpSDK.PARTY_SEND_MESSAGE_OPTIONS sendOptions = PartyCSharpSDK.PARTY_SEND_MESSAGE_OPTIONS.PARTY_SEND_MESSAGE_OPTIONS_SEQUENTIAL_DELIVERY | PartyCSharpSDK.PARTY_SEND_MESSAGE_OPTIONS.PARTY_SEND_MESSAGE_OPTIONS_COALESCE_OPPORTUNISTICALLY; if (!reliable) sendOptions |= PartyCSharpSDK.PARTY_SEND_MESSAGE_OPTIONS.PARTY_SEND_MESSAGE_OPTIONS_BEST_EFFORT_DELIVERY; else sendOptions |= PartyCSharpSDK.PARTY_SEND_MESSAGE_OPTIONS.PARTY_SEND_MESSAGE_OPTIONS_GUARANTEED_DELIVERY; _sendTarget[0] = sendTarget; uint result = PartyCSharpSDK.SDK.PartyEndpointSendMessage(sendPoint, _sendTarget, sendOptions, _sendQueuingConfiguration, _sendBuffer, (uint)(size + 1)); if (PartyCSharpSDK.PartyError.FAILED(result)) { Utils.Debug.LogErro("[PLAYFAB:NETWORK] SendMessage: PartyEndpointSendMessage failed | Result: {0}", result); PlayfabErrorLog.PrintErrorMessage(result); return (Utils.ErrorCode.PLATFORM_SDK); } else return (Utils.ErrorCode.NONE); } } public uint SendGameMessage(PartyCSharpSDK.PARTY_ENDPOINT_HANDLE sendPoint, PartyCSharpSDK.PARTY_ENDPOINT_HANDLE sendTarget, int channel, byte[] data, int size, bool reliable) { if (sendPoint == null) return (Utils.ErrorCode.INVALID_INPUT); if (sendTarget == null) return (Utils.ErrorCode.INVALID_INPUT); lock (_messageLocker) { if (_sendBufferSize < (size + 1 + sizeof(int))) { Utils.Debug.LogWarn("[PLAYFAB:NETWORK] SendMessage: Need to increase send buffer | Current: {0} | Needs: {1}", _sendBufferSize, (size + 1)); SetupSendBuffer((uint)(size + 1 + sizeof(int))); } _sendBufferTag[0] = GAME_MESSAGE; System.Runtime.InteropServices.Marshal.Copy(_sendBufferTag, 0, _sendBuffer, 1); _sendBufferChannel[0] = channel; System.Runtime.InteropServices.Marshal.Copy(_sendBufferChannel, 0, _sendMetaStart, 1); if (0 < size) System.Runtime.InteropServices.Marshal.Copy(data, 0, _sendMessageStart, size); PartyCSharpSDK.PARTY_SEND_MESSAGE_OPTIONS sendOptions = PartyCSharpSDK.PARTY_SEND_MESSAGE_OPTIONS.PARTY_SEND_MESSAGE_OPTIONS_SEQUENTIAL_DELIVERY | PartyCSharpSDK.PARTY_SEND_MESSAGE_OPTIONS.PARTY_SEND_MESSAGE_OPTIONS_COALESCE_OPPORTUNISTICALLY; if (!reliable) sendOptions |= PartyCSharpSDK.PARTY_SEND_MESSAGE_OPTIONS.PARTY_SEND_MESSAGE_OPTIONS_BEST_EFFORT_DELIVERY; else sendOptions |= PartyCSharpSDK.PARTY_SEND_MESSAGE_OPTIONS.PARTY_SEND_MESSAGE_OPTIONS_GUARANTEED_DELIVERY; _sendTarget[0] = sendTarget; uint result = PartyCSharpSDK.SDK.PartyEndpointSendMessage(sendPoint, _sendTarget, sendOptions, _sendQueuingConfiguration, _sendBuffer, (uint)(size + 1 + sizeof(int))); if (PartyCSharpSDK.PartyError.FAILED(result)) { Utils.Debug.LogErro("[PLAYFAB:NETWORK] SendMessage: PartyEndpointSendMessage failed | Result: {0}", result); PlayfabErrorLog.PrintErrorMessage(result); return (Utils.ErrorCode.PLATFORM_SDK); } else return (Utils.ErrorCode.NONE); } } void UpdateParty() { lock (_locker) { if (_partyHandle == null) return; System.Collections.Generic.List stateChanges = null; uint result = PartyCSharpSDK.SDK.PartyStartProcessingStateChanges(_partyHandle, out stateChanges); if (PartyCSharpSDK.PartyError.FAILED(result)) Utils.Debug.Log(Utils.Debug.Level.SPAM | Utils.Debug.Level.ERRO, "[PLAYFAB:PARTYMANAGER] UpdateParty: PartyStartProcessingStateChanges Failed | Result: {0} | Party: {1}", result, _partyHandle); else { Utils.Debug.Log(Utils.Debug.Level.SPAM | Utils.Debug.Level.INFO | Utils.Debug.Level.DEEP, "[PLAYFAB:PARTYMANAGER] UpdateParty: PartyStartProcessingStateChanges Complete | Result: {0} | Party: {1} | Count: {2}", result, _partyHandle, stateChanges.Count); for (int i = 0; i