public override void Tick(int interval)
        {
            NetIncomingMessage msg;

            while ((msg = NetConnector.ReadMessage()) != null)
            {
                switch (msg.MessageType)
                {
                case NetIncomingMessageType.VerboseDebugMessage:
                case NetIncomingMessageType.DebugMessage:
                case NetIncomingMessageType.WarningMessage:
                case NetIncomingMessageType.ErrorMessage:
                    break;

                case NetIncomingMessageType.Error:
                    break;

                case NetIncomingMessageType.StatusChanged:
                    var change           = (NetConnectionStatus)msg.ReadByte();
                    var connectionResult = (NetConnectionResult)msg.ReadByte();
                    OnConnectionStatusChanged(change, connectionResult, msg.SenderConnection);
                    break;

                case NetIncomingMessageType.UnconnectedData:
                    break;

                case NetIncomingMessageType.ConnectionApproval:
                    break;

                case NetIncomingMessageType.Data:
                    NetEncryptor.Decrypt(msg);
                    FilterMessage(msg);
                    break;

                case NetIncomingMessageType.Receipt:
                    break;

                case NetIncomingMessageType.DiscoveryRequest:
                    break;

                case NetIncomingMessageType.DiscoveryResponse:
                    break;

                case NetIncomingMessageType.NatIntroductionSuccess:
                    break;

                case NetIncomingMessageType.ConnectionLatencyUpdated:
                    break;

                default:
                    Console.WriteLine("Unhandled type: " + msg.MessageType);
                    break;
                }
                NetConnector.Recycle(msg);
            }
            RunTasks();
            Task.Delay(interval).Wait();
        }
        public override void Tick(int repeatRate)
        {
            NetIncomingMessage msg;

            while ((msg = NetConnector.ReadMessage()) != null)
            {
                var recycleNow = true;
                switch (msg.MessageType)
                {
                case NetIncomingMessageType.VerboseDebugMessage:
                case NetIncomingMessageType.DebugMessage:
                case NetIncomingMessageType.WarningMessage:
                case NetIncomingMessageType.ErrorMessage:
                    break;

                case NetIncomingMessageType.Error:
                    break;

                case NetIncomingMessageType.StatusChanged:
                    var change           = (NetConnectionStatus)msg.ReadByte();
                    var connectionResult = (NetConnectionResult)msg.ReadByte();
                    OnConnectionStatusChanged(change, connectionResult, msg.SenderConnection);
                    break;

                case NetIncomingMessageType.UnconnectedData:
                    break;

                case NetIncomingMessageType.ConnectionApproval:
                    recycleNow = false;
                    ConnectionApproval(msg);
                    break;

                case NetIncomingMessageType.Data:
                    if (AuthorizedForMessage(msg.SenderConnection))
                    {
                        NetEncryptor.Decrypt(msg);
                        FilterMessage(msg);
                    }
                    break;

                case NetIncomingMessageType.Receipt:
                    break;

                case NetIncomingMessageType.DiscoveryRequest:
                    break;

                case NetIncomingMessageType.DiscoveryResponse:
                    break;

                case NetIncomingMessageType.NatIntroductionSuccess:
                    break;

                case NetIncomingMessageType.ConnectionLatencyUpdated:
                    break;

                default:
                    Log("Unhandled type: " + msg.MessageType);
                    break;
                }
                if (recycleNow)
                {
                    NetConnector.Recycle(msg);
                }
            }
            while (AuthenticationResults.Count > 0)
            {
                var result = AuthenticationResults[0].Item1;
                var user   = AuthenticationResults[0].Item2;
                try
                {
                    if (result.Success)
                    {
                        if (result.Connection.Approve())
                        {
                            OnAuthenticationApproved(result, user);
                        }
                        else
                        {
                            //The request probably took too long
                            OnAuthenticationDenied(result, user);
                        }
                    }
                    else
                    {
                        switch (result.RequestState)
                        {
                        case RequestState.EndpointFailure:
                            result.Connection.Deny(NetConnectionResult.NoResponseFromRemoteHost);
                            break;

                        case RequestState.Success:
                            result.Connection.Deny(NetConnectionResult.Unknown);
                            break;

                        case RequestState.UserAlreadyLoggedIn:
                            result.Connection.Deny(NetConnectionResult.UserAlreadyLoggedIn);
                            break;

                        case RequestState.WrongCredentials:
                            result.Connection.Deny(NetConnectionResult.WrongCredentials);
                            break;

                        default:
                            throw new ArgumentOutOfRangeException();
                        }
                        OnAuthenticationDenied(result, user);
                    }
                }
                catch (Exception e)
                {
                    Log(e);
                    result.Connection.Deny(NetConnectionResult.Unknown);
                    OnAuthenticationDenied(result, user);
                }
                finally
                {
                    AuthenticationResults.Remove(AuthenticationResults[0]);
                }
            }
            RunTasks();
            TickWatch.Stop();
            var interval      = 1000 / repeatRate;
            var elapsedTime   = (int)TickWatch.ElapsedMilliseconds;
            var finalInterval = interval - elapsedTime;

            if (finalInterval > 0)
            {
                Task.Delay(finalInterval).Wait();
            }
            else
            {
                Log($"Tick loop is working overhead at {elapsedTime}ms, configured interval is at {interval}ms");
            }
            TickWatch.Restart();
        }