internal void Dispose()
        {
            CommandHandler?.Dispose(false);
            RealTimeHandler?.Dispose(false);
            TurnBasedHandler?.Dispose(false);

            CommandHandler   = null;
            RealTimeHandler  = null;
            TurnBasedHandler = null;

            try
            {
                GC.SuppressFinalize(this);
            }
            catch (Exception)
            {
                // ignored
            }
        }
        private void OnDispose(object sender, DisposeData disposeData)
        {
            switch (disposeData.Type)
            {
            case GSLiveType.RealTime:
                RealTimeHandler?.Dispose(disposeData.IsGraceful);
                RealTimeHandler = null;
                GsSerializer.CurrentPlayerLeftRoom?.Invoke(this, null);
                break;

            case GSLiveType.TurnBased:
                TurnBasedHandler?.Dispose(disposeData.IsGraceful);
                TurnBasedHandler = null;
                break;

            case GSLiveType.NotSet:
            case GSLiveType.Command:
            case GSLiveType.Voice:
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(disposeData), disposeData, null);
            }
        }