From 64842886d72665bf74f66f06b3f8450b6f34b569 Mon Sep 17 00:00:00 2001 From: edmand46 Date: Sat, 7 Oct 2023 20:20:02 +0300 Subject: [PATCH] :sparkles: multiple subscribers, and unsubscribe --- Ragon.Client/Sources/Entity/RagonEntity.cs | 53 +++++++++++++++----- Ragon.Client/Sources/RagonRoom.cs | 57 ++++++++++++++++------ 2 files changed, 82 insertions(+), 28 deletions(-) diff --git a/Ragon.Client/Sources/Entity/RagonEntity.cs b/Ragon.Client/Sources/Entity/RagonEntity.cs index 6a6ad6a..1d03787 100644 --- a/Ragon.Client/Sources/Entity/RagonEntity.cs +++ b/Ragon.Client/Sources/Entity/RagonEntity.cs @@ -50,7 +50,8 @@ namespace Ragon.Client private RagonPayload _destroyPayload; private readonly Dictionary _events = new Dictionary(); - private readonly Dictionary> _localEvents = new Dictionary>(); + private readonly Dictionary>> _localListeners = new Dictionary>>(); + private readonly Dictionary>> _listeners = new Dictionary>>(); public RagonEntity(ushort type = 0, ushort sceneId = 0) { @@ -155,12 +156,16 @@ namespace Ragon.Client { if (replicationMode == RagonReplicationMode.Local) { - _localEvents[eventCode].Invoke(_client.Room.Local, evnt); + var localListeners = _localListeners[eventCode]; + foreach (var listener in localListeners) + listener.Invoke(_client.Room.Local, evnt); return; } if (replicationMode == RagonReplicationMode.LocalAndServer) { - _localEvents[eventCode].Invoke(_client.Room.Local, evnt); + var localListeners = _localListeners[eventCode]; + foreach (var listener in localListeners) + listener.Invoke(_client.Room.Local, evnt); } } @@ -179,25 +184,49 @@ namespace Ragon.Client _client.Reliable.Send(sendData); } - public void OnEvent(Action callback) where TEvent : IRagonEvent, new() + public Action OnEvent(Action callback) where TEvent : IRagonEvent, new() { var t = new TEvent(); var eventCode = _client.Event.GetEventCode(t); - - if (_events.ContainsKey(eventCode)) + var callbacks = _listeners[eventCode]; + var action = (RagonPlayer player, IRagonEvent eventData) => callback.Invoke(player, (TEvent)eventData); + + if (callbacks == null) { - _events.Remove(eventCode); - _localEvents.Remove(eventCode); - - RagonLog.Warn($"Event already {eventCode} subscribed, removed old one!"); + callbacks = new List>(); + _listeners.Add(eventCode, callbacks); } - _localEvents.Add(eventCode, (player, eventData) => { callback.Invoke(player, (TEvent)eventData); }); + var localCallbacks = _localListeners[eventCode]; + if (localCallbacks == null) + { + localCallbacks = new List>(); + _localListeners.Add(eventCode, callbacks); + } + + callbacks.Add(action); + localCallbacks.Add(action); + _events.Add(eventCode, (player, serializer) => { t.Deserialize(serializer); - callback.Invoke(player, t); + + foreach (var callbackListener in callbacks) + callbackListener.Invoke(player, t); }); + + return action; + } + + public void OffEvent(Action callback) where TEvent : IRagonEvent, new() + { + var t = new TEvent(); + var eventCode = _client.Event.GetEventCode(t); + var callbacks = _listeners[eventCode]; + var localCallbacks = _localListeners[eventCode]; + + callbacks?.Remove(callback); + localCallbacks?.Remove(callback); } internal void Write(RagonBuffer buffer) diff --git a/Ragon.Client/Sources/RagonRoom.cs b/Ragon.Client/Sources/RagonRoom.cs index 2532a7f..7a9d2b9 100644 --- a/Ragon.Client/Sources/RagonRoom.cs +++ b/Ragon.Client/Sources/RagonRoom.cs @@ -21,13 +21,13 @@ namespace Ragon.Client public class RagonRoom { private delegate void OnEventDelegate(RagonPlayer player, RagonBuffer serializer); - + private RagonClient _client; private RagonScene _scene; private RagonEntityCache _entityCache; private RagonPlayerCache _playerCache; private RagonRoomInformation _information; - + public string Id => _information.RoomId; public int MinPlayers => _information.Min; public int MaxPlayers => _information.Max; @@ -36,10 +36,11 @@ namespace Ragon.Client public IReadOnlyList Players => _playerCache.Players; public RagonPlayer Local => _playerCache.Local; public RagonPlayer Owner => _playerCache.Owner; - + private readonly Dictionary _events = new Dictionary(); - private readonly Dictionary> _localEvents = new Dictionary>(); - + private readonly Dictionary>> _localListeners = new Dictionary>>(); + private readonly Dictionary>> _listeners = new Dictionary>>(); + public RagonRoom(RagonClient client, RagonEntityCache entityCache, RagonPlayerCache playerCache, @@ -71,31 +72,55 @@ namespace Ragon.Client else RagonLog.Warn($"Handler event on entity {Id} with eventCode {eventCode} not defined"); } - - public void OnEvent(Action callback) where TEvent : IRagonEvent, new() + + public Action OnEvent(Action callback) where TEvent : IRagonEvent, new() { var t = new TEvent(); var eventCode = _client.Event.GetEventCode(t); - - if (_events.ContainsKey(eventCode)) + var callbacks = _listeners[eventCode]; + var action = (RagonPlayer player, IRagonEvent eventData) => callback.Invoke(player, (TEvent)eventData); + + if (callbacks == null) { - _events.Remove(eventCode); - _localEvents.Remove(eventCode); - - RagonLog.Warn($"Event already {eventCode} subscribed, removed old one!"); + callbacks = new List>(); + _listeners.Add(eventCode, callbacks); } - _localEvents.Add(eventCode, (player, eventData) => { callback.Invoke(player, (TEvent)eventData); }); + var localCallbacks = _localListeners[eventCode]; + if (localCallbacks == null) + { + localCallbacks = new List>(); + _localListeners.Add(eventCode, callbacks); + } + + callbacks.Add(action); + localCallbacks.Add(action); + _events.Add(eventCode, (player, serializer) => { t.Deserialize(serializer); - callback.Invoke(player, t); + + foreach (var callbackListener in callbacks) + callbackListener.Invoke(player, t); }); + + return action; + } + + public void OffEvent(Action callback) where TEvent : IRagonEvent, new() + { + var t = new TEvent(); + var eventCode = _client.Event.GetEventCode(t); + var callbacks = _listeners[eventCode]; + var localCallbacks = _localListeners[eventCode]; + + callbacks?.Remove(callback); + localCallbacks?.Remove(callback); } public void LoadScene(string sceneName) => _scene.Load(sceneName); public void SceneLoaded() => _scene.SceneLoaded(); - + public void ReplicateEvent(TEvent evnt, RagonTarget target, RagonReplicationMode mode) where TEvent : IRagonEvent, new() => _scene.ReplicateEvent(evnt, target, mode); public void ReplicateEvent(TEvent evnt, RagonPlayer target, RagonReplicationMode mode) where TEvent : IRagonEvent, new() => _scene.ReplicateEvent(evnt, target, mode);