예제 #1
0
        // static

        public static MinecraftConfiguration FromFile(string filename)
        {
            var config = new MinecraftConfiguration(filename);

            var lines = File.ReadAllLines(filename);

            for (int i = 0; i < lines.Length; ++i)
            {
                lines[i] = lines[i].Trim();

                if (!lines[i].StartsWith("#") &&
                    lines[i].Length > 0)
                {
                    var pos = lines[i].IndexOf('=');
                    if (pos != -1)
                    {
                        var key   = lines[i].Substring(0, pos).Trim();
                        var value = lines[i].Substring(pos + 1).Trim();

                        if (key.Length > 0)
                        {
                            config._properties.Add(key, value);
                        }
                    }
                }
            }

            //config._properties
            return(config);
        }
예제 #2
0
            private void WorkerThread()
            {
                if (!File.Exists(_package.Filename))
                {
                    _logger.Write(
                        LogType.Error,
                        $"Failed to start instance. Physical package file '{_package.Name}' ('{_package.Filename}') not found.");
                    Exception = new FileNotFoundException("The package file does not exist.", _package.Filename);
                    SetStatus(InstanceStatus.Error);
                    return;
                }

                SetStatus(InstanceStatus.Starting);

                var instanceDirectory = Path.Combine(Environment.CurrentDirectory, "instances", _id);

                Directory.CreateDirectory(instanceDirectory);

                // extract instance into a new folder and so forth
                try
                {
                    using (var stream = File.Open(_package.Filename, FileMode.Open, FileAccess.Read, FileShare.Read))
                        using (var archive = new ZipArchive(stream))
                        {
                            archive.ExtractToDirectory(instanceDirectory);
                        }
                }
                catch (Exception ex)
                {
                    Directory.Delete(instanceDirectory);
                    _logger.Write(
                        LogType.Error,
                        $"Failed to start instance. Exception extracting package '{_package.Name}' ('{_package.Filename}') => ({ex.GetType().Name}) {ex.Message}");
                    Exception = ex;
                    SetStatus(InstanceStatus.Error);
                    return;
                }

                // always set the eula to true regardless of the package
                File.WriteAllText(Path.Combine(instanceDirectory, "eula.txt"), "eula=true\r\n");

                // Configure the instance based on given settings
                var minecraftConfig = MinecraftConfiguration.FromFile(Path.Combine(instanceDirectory, "server.properties"));

                minecraftConfig.SetValue("snooper-enabled", "false"); // don't send snoop data to snoop.minecraft.net

                foreach (var extraConfiguration in Configuration.ExtraConfigurationValues)
                {
                    minecraftConfig.SetValue(extraConfiguration.Key, extraConfiguration.Value);
                }

                minecraftConfig.SetValue("motd", Configuration.Motd);
                minecraftConfig.SetValue("enable-command-block", Configuration.EnableCommandBlocks);
                minecraftConfig.SetValue("max-players", Configuration.MaxPlayers);
                minecraftConfig.SetValue("announce-player-achievements", Configuration.AnnouncePlayerAchievements);

                // network
                minecraftConfig.SetValue("server-ip", _bindingInterface.IP != "0.0.0.0" ? _bindingInterface.IP : "");
                minecraftConfig.SetValue("server-port", _bindingInterface.Port);

                minecraftConfig.Save();

                try
                {
                    // start process
                    var psi = new ProcessStartInfo(
                        Configuration.JavaExecutable,
                        $"-Xmx{Configuration.JavaMaximumMemoryMegabytes}M -Xms{Configuration.JavaInitialMemoryMegabytes}M -jar \"{Configuration.MinecraftJarFilename}\" nogui");
                    psi.UseShellExecute        = false;
                    psi.RedirectStandardInput  = true;
                    psi.RedirectStandardOutput = true;
                    psi.CreateNoWindow         = true;
                    psi.WorkingDirectory       = instanceDirectory;

                    Process process;
                    try
                    {
                        process = Process.Start(psi);

                        if (process == null)
                        {
                            throw new Exception("Process.Start returned null");
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.Write(LogType.Error, $"Exception in starting process: ({ex.GetType().Name}) {ex.Message}");
                        _logger.Write(LogType.Error, $"- Filename: {psi.FileName}");
                        _logger.Write(LogType.Error, $"- Arguments: {psi.Arguments}");
                        _logger.Write(LogType.Error, $"- Directory: {psi.WorkingDirectory}");
                        Exception = ex;
                        SetStatus(InstanceStatus.Error);
                        return;
                    }

                    _logger.Write(LogType.Notice, $"Started instance {_id}");

                    var timeMatch   = new Regex(@"^\s*\[\d+:\d+(:\d+)?\]\s*");
                    var prefixMatch = new Regex(@"^\s*\[.*?\]:\s*"); // [Server thread/INFO]: etc..

                    using (process)
                    {
                        DateTime?stopTime = null;

                        process.OutputDataReceived += (sender, e) =>
                        {
                            if (e.Data != null)
                            {
                                string msg;

                                var match = timeMatch.Match(e.Data);
                                if (match.Success)
                                {
                                    msg = e.Data.Substring(match.Index + match.Length);
                                }
                                else
                                {
                                    msg = e.Data;
                                }

                                if ((match = prefixMatch.Match(msg)).Success)
                                {
                                    msg = msg.Substring(match.Index + match.Length);
                                }

                                InstanceLogManager.AddLog(_id, msg);

                                _logger.Write(LogType.Normal, "[MC] " + msg);
                                foreach (var listener in _instanceManager._instanceEventListeners)
                                {
                                    listener.OnInstanceLog(_id, DateTime.UtcNow, msg);
                                }

                                if (msg.StartsWith("Done ("))
                                {
                                    SetStatus(InstanceStatus.Running);
                                }
                            }
                        };

                        process.BeginOutputReadLine();

                        // set process?
                        bool sentShutdown = false;

                        var waitEvents = new WaitHandle[] { _executeCommandEvent, _shutdownEvent, _terminateEvent };

                        while (!process.HasExited)
                        {
                            if (!sentShutdown &&
                                stopTime.HasValue &&
                                DateTime.UtcNow >= stopTime)
                            {
                                sentShutdown = true;
                                _logger.Write(LogType.Warning, "Sending stop command ...");
                                process.StandardInput.WriteLine("stop");

                                SetStatus(InstanceStatus.Stopping);
                            }

                            int n = WaitHandle.WaitAny(waitEvents, 100); // WaitHandle.WaitTimeout on timeout ...
                            if (n == 0)                                  //_executeCommandEvent.WaitOne(100))
                            {
                                LinkedList <string> commands;
                                lock (_commandLock)
                                {
                                    commands      = _commandQueue;
                                    _commandQueue = new LinkedList <string>();
                                }

                                foreach (var command in commands)
                                {
                                    process.StandardInput.WriteLine(command);
                                }
                            }
                            else if (n == 1) // gracefully shutdown
                            {
                                if (!stopTime.HasValue)
                                {
                                    stopTime = DateTime.UtcNow.AddSeconds(1);
                                }
                            }
                            else if (n == 2) // terminate process
                            {
                                // terminate
                                _logger.Write(LogType.Warning, $"Instance {_id} forcefully killed.");
                                process.Kill();
                            }
                        }

                        process.CancelOutputRead();
                    }

                    _logger.Write(LogType.Notice, $"Instance {_id} stopped");
                    SetStatus(InstanceStatus.Stopped);
                }
                catch (Exception ex)
                {
                    _logger.Write(LogType.Error, $"Instance loop exception detected: ({ex.GetType().Name}) {ex.Message}");
                    Exception = ex;
                    SetStatus(InstanceStatus.Error);
                }

                InstanceLogManager.Remove(_id);

                // delete instance
                while (true)
                {
                    try
                    {
                        Directory.Delete(instanceDirectory, true);
                        break;
                    }
                    catch
                    {
                        Thread.Sleep(500);
                    }
                }
            }