protected override void Dispose(bool disposing)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            if (disposing)
            {
                #region CLEAN THIS UP

                // TODO: This may actually be fine here? Might want to move it into Bootstrapper though as "PrintShutdown()"
                Console.WriteLine();
                Console.WriteLine(Strings.Commands.exiting);
                Console.WriteLine();

#if WEBSOCKETS
                Log.Info("Shutting down websockets..." + $" ({stopwatch.ElapsedMilliseconds}ms)");
                WebSocketNetwork.Stop();
#endif

                // Except this line, this line is fine.
                Log.Info("Disposing network..." + $" ({stopwatch.ElapsedMilliseconds}ms)");
                Network.Dispose();

                // TODO: This probably also needs to not be a global, but will require more work to clean up.
                Log.Info("Saving player database..." + $" ({stopwatch.ElapsedMilliseconds}ms)");
                DbInterface.SavePlayerDatabase(Environment.StackTrace);
                Log.Info("Saving game database..." + $" ({stopwatch.ElapsedMilliseconds}ms)");
                DbInterface.SaveGameDatabase();

                // TODO: This needs to not be a global. I'm also in the middle of rewriting the API anyway.
                Log.Info("Shutting down the API..." + $" ({stopwatch.ElapsedMilliseconds}ms)");
                RestApi.Dispose();

                #endregion

                if (ThreadConsole?.IsAlive ?? false)
                {
                    Log.Info("Shutting down the console thread..." + $" ({stopwatch.ElapsedMilliseconds}ms)");
                    if (!ThreadConsole.Join(1000))
                    {
                        try
                        {
                            ThreadConsole.Abort();
                        }
                        catch (ThreadAbortException threadAbortException)
                        {
                            Log.Error(threadAbortException, $"{nameof(ThreadConsole)} aborted.");
                        }
                    }
                }

                if (ThreadLogic?.IsAlive ?? false)
                {
                    Log.Info("Shutting down the logic thread..." + $" ({stopwatch.ElapsedMilliseconds}ms)");
                    if (!ThreadLogic.Join(10000))
                    {
                        try
                        {
                            ThreadLogic.Abort();
                        }
                        catch (ThreadAbortException threadAbortException)
                        {
                            Log.Error(threadAbortException, $"{nameof(ThreadLogic)} aborted.");
                        }
                    }
                }
            }

            Log.Info("Base dispose." + $" ({stopwatch.ElapsedMilliseconds}ms)");
            base.Dispose(disposing);
            Log.Info("Finished disposing server context." + $" ({stopwatch.ElapsedMilliseconds}ms)");
            Console.WriteLine(Strings.Commands.exited);
        }
        protected override void Dispose(bool disposing)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            if (disposing)
            {
                #region CLEAN THIS UP

                // TODO: This may actually be fine here? Might want to move it into Bootstrapper though as "PrintShutdown()"
                Console.WriteLine();
                Console.WriteLine(Strings.Commands.exiting);
                Console.WriteLine();

#if WEBSOCKETS
                Log.Info("Shutting down websockets..." + $" ({stopwatch.ElapsedMilliseconds}ms)");
                WebSocketNetwork.Stop();
#endif

                // Except this line, this line is fine.
                Log.Info("Disposing network..." + $" ({stopwatch.ElapsedMilliseconds}ms)");
                Network.Dispose();

                // TODO: This probably also needs to not be a global, but will require more work to clean up.
                Log.Info("Saving online users/players..." + $" ({stopwatch.ElapsedMilliseconds}ms)");

                var savingTasks = new List <Task>();
                foreach (var user in Database.PlayerData.User.OnlineList.ToArray())
                {
                    savingTasks.Add(Task.Run(() => user.Save()));
                }

                Task.WaitAll(savingTasks.ToArray());

                // TODO: This probably also needs to not be a global, but will require more work to clean up.
                Log.Info("Online users/players saved." + $" ({stopwatch.ElapsedMilliseconds}ms)");


                //Disconnect All Clients
                //Will kill their packet handling threads so we have a clean shutdown
                lock (Globals.ClientLock)
                {
                    var clients = Globals.Clients.ToArray();
                    foreach (var client in clients)
                    {
                        client.Disconnect("Server Shutdown", true);
                    }
                }


                // TODO: This needs to not be a global. I'm also in the middle of rewriting the API anyway.
                Log.Info("Shutting down the API..." + $" ({stopwatch.ElapsedMilliseconds}ms)");
                RestApi.Dispose();

                #endregion

                if (ThreadConsole?.IsAlive ?? false)
                {
                    Log.Info("Shutting down the console thread..." + $" ({stopwatch.ElapsedMilliseconds}ms)");
                    if (!ThreadConsole.Join(1000))
                    {
                        try
                        {
                            ThreadConsole.Abort();
                        }
                        catch (ThreadAbortException threadAbortException)
                        {
                            Log.Error(threadAbortException, $"{nameof( ThreadConsole )} aborted.");
                        }
                    }
                }

                if (ThreadLogic?.IsAlive ?? false)
                {
                    Log.Info("Shutting down the logic thread..." + $" ({stopwatch.ElapsedMilliseconds}ms)");
                    if (!ThreadLogic.Join(10000))
                    {
                        try
                        {
                            ThreadLogic.Abort();
                        }
                        catch (ThreadAbortException threadAbortException)
                        {
                            Log.Error(threadAbortException, $"{nameof( ThreadLogic )} aborted.");
                        }
                    }
                }

                NetworkHelper.HandlerRegistry.Dispose();
            }

            Log.Info("Base dispose." + $" ({stopwatch.ElapsedMilliseconds}ms)");
            base.Dispose(disposing);
            Log.Info("Finished disposing server context." + $" ({stopwatch.ElapsedMilliseconds}ms)");
            Console.WriteLine(Strings.Commands.exited);
            System.Environment.Exit(-1);
        }