public static void Start(params string[] args) { (string[] Args, Parser Parser, ServerCommandLineOptions CommandLineOptions)parsedArguments = ParseCommandLineArgs(args); if (!string.IsNullOrWhiteSpace(parsedArguments.CommandLineOptions.WorkingDirectory)) { var workingDirectory = parsedArguments.CommandLineOptions.WorkingDirectory.Trim(); if (Directory.Exists(workingDirectory)) { Directory.SetCurrentDirectory(workingDirectory); } } if (!PreContextSetup(args)) { return; } var logger = Log.Default; var packetTypeRegistry = new PacketTypeRegistry(logger); if (!packetTypeRegistry.TryRegisterBuiltIn()) { logger.Error("Failed to load built-in packet types."); return; } var packetHandlerRegistry = new PacketHandlerRegistry(packetTypeRegistry, logger); var networkHelper = new NetworkHelper(packetTypeRegistry, packetHandlerRegistry); FactoryRegistry <IPluginBootstrapContext> .RegisterFactory( PluginBootstrapContext.CreateFactory( parsedArguments.Args ?? Array.Empty <string>(), parsedArguments.Parser, networkHelper ) ); Context = new ServerContext(parsedArguments.CommandLineOptions, logger, networkHelper); var noHaltOnError = Context?.StartupOptions.DoNotHaltOnError ?? false; if (!PostContextSetup()) { return; } MainThread = Context.StartWithActionQueue(); Action action; while (null != (action = MainThread.NextAction)) { action.Invoke(); } Log.Diagnostic("Bootstrapper exited."); // At this point dbs should be saved and all threads should be killed. Give a message saying that the server has shutdown and to press any key to exit. // Having the message and the console.readline() allows the server to exit properly if the console has crashed, and it allows us to know that the server context has shutdown. if (Context.HasErrors) { if (noHaltOnError) { Console.WriteLine(Strings.Errors.errorservercrashnohalt); } else { Console.WriteLine(Strings.Errors.errorservercrash); Console.ReadLine(); } } }