protected override void EventHandler(RealtimeEvent @event)
        {
            base.EventHandler(@event);

            if (@event is RelayRealtimeEvent relayEvent)
            {
                switch (relayEvent.EventType)
                {
                case RelayRealtimeEventType.OnRelayMessage:
                    OnRelayMessageWithMetadataEvent relayMessageEvent = relayEvent as OnRelayMessageWithMetadataEvent;
                    if (OnRelayMessage != null)
                    {
                        OnRelayMessage.Invoke(relayMessageEvent.Message);
                    }
                    if (OnRelayMessageWithMetadata != null)
                    {
                        OnRelayMessageWithMetadata.Invoke(relayMessageEvent.Message, relayMessageEvent.Metadata);
                    }
                    break;
                }
            }
        }
        protected virtual void EventHandler(RealtimeEvent @event)
        {
            switch (@event.EventType)
            {
            case RealtimeEventType.OnMessage:
            {
                var typedEvent = @event as OnMessageEvent;
                if (OnMessage != null)
                {
                    OnMessage.Invoke(typedEvent.Message);
                }

                if (OnMessageWithMetadata != null)
                {
                    OnMessageWithMetadata.Invoke(typedEvent.Message, typedEvent.Metadata);
                }

                break;
            }

            case RealtimeEventType.OnJoinPlayer:
            {
                var typedEvent = @event as OnJoinPlayerEvent;
                if (OnJoinPlayer != null)
                {
                    OnJoinPlayer.Invoke(typedEvent.Player);
                }

                if (OnJoinPlayerWithMetadata != null)
                {
                    OnJoinPlayerWithMetadata.Invoke(typedEvent.Player, typedEvent.Metadata);
                }

                break;
            }

            case RealtimeEventType.OnLeavePlayer:
            {
                var typedEvent = @event as OnLeavePlayerEvent;
                if (OnLeavePlayer != null)
                {
                    OnLeavePlayer.Invoke(typedEvent.Player);
                }

                if (OnLeavePlayerWithMetadata != null)
                {
                    OnLeavePlayerWithMetadata.Invoke(typedEvent.Player, typedEvent.Metadata);
                }

                break;
            }

            case RealtimeEventType.OnUpdateProfile:
            {
                var typedEvent = @event as OnUpdateProfileEvent;
                if (OnUpdateProfile != null)
                {
                    OnUpdateProfile.Invoke(typedEvent.Player);
                }

                if (OnUpdateProfileWithMetadata != null)
                {
                    OnUpdateProfileWithMetadata.Invoke(typedEvent.Player, typedEvent.Metadata);
                }

                break;
            }

            case RealtimeEventType.OnError:
            {
                var typedEvent = @event as OnErrorEvent;
                if (OnError != null)
                {
                    OnError.Invoke(typedEvent.Error);
                }

                if (OnErrorWithMetadata != null)
                {
                    OnErrorWithMetadata.Invoke(typedEvent.Error, typedEvent.Metadata);
                }

                break;
            }

            case RealtimeEventType.OnGeneralError:
                if (OnGeneralError != null)
                {
                    OnGeneralError.Invoke((@event as OnGeneralErrorEvent).Error);
                }

                break;

            case RealtimeEventType.OnClose:
                if (OnClose != null)
                {
                    OnClose.Invoke((@event as OnCloseEvent).Error);
                }

                break;

            case RealtimeEventType.PluginEventType:
                break;
            }
        }