예제 #1
0
        /// <summary>
        /// Run the command, which should open Minecraft. Assuming everything else is filled in as intended.
        /// </summary>
        /// <returns>Status of exceptions or success</returns>
        private Process RunCommand(MinecraftSession session, IGameProcessMonitor monitor)
        {
            string args = FormatArguments(session);
            string javaFile = FileUtility.FindOnPath(JavaFile);

            if (javaFile == null)
                javaFile = JavaFile;

            Logger.Debug("Starting minecraft:");
            Logger.Debug ("{0} {1}", javaFile, args);

            monitor.OutputLine(GameMessageType.Output, "Starting minecraft:");
            monitor.OutputLine(GameMessageType.Output, string.Format("{0} {1}", javaFile, args));

            Process mcProc = new Process();
            mcProc.StartInfo.UseShellExecute = false;
            mcProc.StartInfo.WorkingDirectory = GameLocation;
            mcProc.StartInfo.FileName = javaFile;
            mcProc.StartInfo.Arguments = args;
            mcProc.StartInfo.RedirectStandardOutput = true;
            mcProc.StartInfo.RedirectStandardError = true;

            try {
                mcProc.Start();

                if (CPUPriority == "Realtime") {
                    mcProc.PriorityClass = ProcessPriorityClass.RealTime;
                } else if (CPUPriority == "High") {
                    mcProc.PriorityClass = ProcessPriorityClass.High;
                } else if (CPUPriority == "Above Normal") {
                    mcProc.PriorityClass = ProcessPriorityClass.AboveNormal;
                } else if (CPUPriority == "Below Normal") {
                    mcProc.PriorityClass = ProcessPriorityClass.BelowNormal;
                }

                return mcProc;
            } catch (Exception e) {
                Logger.Debug(e);
                throw e;
            }
        }
예제 #2
0
        /// <summary>
        /// Starts Minecraft. This method will call Setup() to ensure that all needed assets, libraries, and 
        /// the needed game version are downloaded into the various cache directories, and installed into 
        /// the folder listed at GameFolder. If you are using a verison of Minecraft prior to 1.7.4, we will
        /// verify the contents of assets/legacy/virtual are exactly the same as those listed in the 
        /// Minecraft asset manifest associated to the version being launched. Any mismatches will be replaced
        /// from the asset cache.
        /// </summary>
        /// <param name="authSession">
        /// The Minecraft authentication session to use while launching the game. To obtain one of these,
        /// construct a MinecraftAuthentication instance and call the Login() method, giving a valid Minecraft
        /// username and password.
        /// </param>
        /// <param name="monitor">
        /// Receives events related to the Minecraft game process. Events will be received on a foreign thread,
        /// You as the caller MUST ensure that you perform any operations within the correct thread. Many user 
        /// interface frameworks are single-threaded by default, and thus require you to pass a message to the 
        /// UI thread from the game monitor thread which calls your IGameMonitor instance. Please do not report
        /// problems to us or your UI framework because you aren't doing threading correctly. We cannot stress
        /// enough to learn the basics of the C# lock() statement and also System.Collections.Generic.Queue<T>. 
        /// </param>
        /// <returns></returns>
        public Process Start(MinecraftSession authSession, IGameProcessMonitor monitor)
        {
            Username = authSession.OriginalUsername;
            Setup();
            GetNatives();

            // Run Minecraft, with a pair of threads for pumping messages out of StandardError/Output and into
            // a queue, which we pick up with a third "mediator" thread, which handles calling the IGameMonitor passed
            // by the caller.

            var proc = RunCommand(authSession, monitor);
            Queue<GameMessage> messages = new Queue<GameMessage>();

            var waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
            var stdErrThread = new Thread(GenerateGameMessagePumper(proc.StandardError, GameMessageType.Error, messages, waitHandle));
            var stdOutThread = new Thread(GenerateGameMessagePumper(proc.StandardOutput, GameMessageType.Output, messages, waitHandle));

            var monitorThread = new Thread(delegate (object state) {
                while (true) {
                    waitHandle.WaitOne(new TimeSpan(0, 0, 0, 0, 100));

                    if (proc.HasExited && !stdErrThread.IsAlive && !stdOutThread.IsAlive) {
                        Console.WriteLine("Minecraft appears to have exited ({0}) and all thread activity is completed.", proc.ExitCode);
                        break;
                    }

                    lock (messages) {
                        if (messages.Count == 0)
                            continue;

                        // Call the monitor to report this output line.
                        // Note that this occurs in OUR thread. You, as the receiver of this
                        // event, need to make sure you perform operations therein in the proper
                        // thread. Learn to use Queues and always lock em.

                        int max = Math.Min(100, messages.Count);

                        for (int i = 0; i < max; ++i) {
                            var msg = messages.Dequeue();
                            Console.WriteLine(msg.Line);
                            monitor.OutputLine(msg.Type, msg.Line);
                        }
                    }
                }

                // Game has ended
                monitor.GameEnded(proc.ExitCode);
            });

            Console.WriteLine("Starting monitor threads...");
            stdErrThread.Name = "Minecraft-StdErr";
            stdErrThread.IsBackground = true;
            stdErrThread.Start();
            stdOutThread.Name = "Minecraft-StdOut";
            stdOutThread.IsBackground = true;
            stdOutThread.Start();
            monitorThread.Name = "Minecraft-Monitor";
            monitorThread.IsBackground = true;
            monitorThread.Start();

            Console.WriteLine("Game has started, returning control to UI...");

            return proc;
        }