/// <summary> /// Handles a console command. /// </summary> /// <param name="sender">The sending object.</param> /// <param name="e">The event data.</param> public void CommandInputHandle(object sender, ConsoleCommandEventArgs e) { Schedule.ScheduleSyncTask(() => { Commands.ExecuteCommands(e.Command); }); }
/// <summary> /// Starts up and run the server. /// </summary> /// <param name="game">The game name.</param> /// <param name="loaded">The action to fire when the server is loaded.</param> public void StartUp(string game, Action loaded = null) { CurThread = Thread.CurrentThread; Files = new FileHandler(); GameName = FileHandler.CleanFileName(game); Files.SetSaveDirEarly("server_" + GameName); SysConsole.Written += OnConsoleWritten; SysConsole.Output(OutputType.INIT, "Launching as new server, this is " + (this == Central ? "" : "NOT ") + "the Central server."); SysConsole.Output(OutputType.INIT, "Loading console input handler..."); ConsoleHandler.Init(); ConsoleHandler.OnCommandInput += CommandInputHandle; SysConsole.Output(OutputType.INIT, "Loading command engine..."); Commands = new ServerCommands(); Commands.Init(new ServerOutputter(this), this); SysConsole.Output(OutputType.INIT, "Loading CVar engine..."); CVars = new ServerCVar(); CVars.Init(this, Commands.Output); SysConsole.Output(OutputType.INIT, "Loading default settings..."); Config = new FDSSection(Files.ReadText("server_config.fds")); Settings = new ServerSettings(this, Config); if (Files.Exists("serverdefaultsettings.cfg")) { string contents = Files.ReadText("serverdefaultsettings.cfg"); Commands.ExecuteCommands(contents); } if (Files.Exists("server_eid.txt")) { cID = long.Parse(Files.ReadText("server_eid.txt") ?? "1"); } SysConsole.Output(OutputType.INIT, "Loading player command engine..."); PCEngine = new PlayerCommandEngine(); SysConsole.Output(OutputType.INIT, "Loading permissions engine..."); PermGroups = new PermissionsGroupEngine() { TheServer = this }; SysConsole.Output(OutputType.INIT, "Loading item registry..."); ItemInfos = new ItemInfoRegistry(); Items = new ItemRegistry(this); Recipes = new RecipeRegistry() { TheServer = this }; SysConsole.Output(OutputType.INIT, "Loading model handler..."); Models = new ModelEngine(this); SysConsole.Output(OutputType.INIT, "Loading animation handler..."); Animations = new AnimationEngine(); SysConsole.Output(OutputType.INIT, "Preparing networking..."); Networking = new NetworkBase(this); Networking.Init(); SysConsole.Output(OutputType.INIT, "Loading plugins..."); Plugins = new PluginManager(this); Plugins.Init(); SysConsole.Output(OutputType.INIT, "Loading scripts..."); AutorunScripts(); SysConsole.Output(OutputType.INIT, "Building initial world(s)..."); foreach (string str in Settings.Worlds) { LoadWorld(str.ToLowerFast()); } SysConsole.Output(OutputType.INIT, "Preparing block image system..."); BlockImages = new BlockImageManager(); BlockImages.Init(this); loaded?.Invoke(); SysConsole.Output(OutputType.INIT, "Ticking..."); // Tick double TARGETFPS = 30d; Stopwatch Counter = new Stopwatch(); Stopwatch DeltaCounter = new Stopwatch(); DeltaCounter.Start(); double TotalDelta = 0; double CurrentDelta = 0d; double TargetDelta = 0d; int targettime = 0; try { while (true) { // Update the tick time usage counter Counter.Reset(); Counter.Start(); // Update the tick delta counter DeltaCounter.Stop(); // Delta time = Elapsed ticks * (ticks/second) CurrentDelta = ((double)DeltaCounter.ElapsedTicks) / ((double)Stopwatch.Frequency); // Begin the delta counter to find out how much time is /really/ slept+ticked for DeltaCounter.Reset(); DeltaCounter.Start(); // How much time should pass between each tick ideally TARGETFPS = Settings.FPS; if (TARGETFPS < 1 || TARGETFPS > 600) { Settings.FPS = 30; TARGETFPS = 30; } TargetDelta = (1d / TARGETFPS); // How much delta has been built up TotalDelta += CurrentDelta; while (TotalDelta > TargetDelta * 3) { // Lagging - cheat to catch up! TargetDelta *= 2; } // As long as there's more delta built up than delta wanted, tick while (TotalDelta > TargetDelta) { if (NeedShutdown.IsCancellationRequested) { CurThread = Thread.CurrentThread; ShutDown(ShutdownCallback); return; } else if (NeedsQuickShutdown.IsCancellationRequested) { CurThread = Thread.CurrentThread; ShutDownQuickly(); return; } lock (TickLock) { Tick(TargetDelta); } TotalDelta -= TargetDelta; } // The tick is done, stop measuring it Counter.Stop(); // Only sleep for target milliseconds/tick minus how long the tick took... this is imprecise but that's okay targettime = (int)((1000d / TARGETFPS) - Counter.ElapsedMilliseconds); // Only sleep at all if we're not lagging if (targettime > 0) { // Try to sleep for the target time - very imprecise, thus we deal with precision inside the tick code Thread.Sleep(targettime); } } } catch (ThreadAbortException) { return; } }