public MainWindow(Instance instance, MinecraftSession session) : base(Gtk.WindowType.Toplevel) { Instance = instance; Session = session; Build (); titleLabel.Text = instance.Description.Name; if (session != null) usernameLabel.Markup = string.Format ("Logged in as <b>{0}</b>", Session.Username); else { var saved = GetSavedCredentials(); if (saved == null) { usernameLabel.Markup = string.Format ("Click Play to Login"); } else { usernameLabel.Markup = string.Format ("Welcome back <b>{0}</b>!", saved.AutoLoginUser); } } var syncSummary = instance.CheckSync(); List<string> items = new List<string>(); items.AddRange(syncSummary.UpgradedMods.Select( mod => string.Format ("Upgraded mod: {0} {1}", mod.NewVersion.Name, mod.NewVersion.Version) )); items.AddRange(syncSummary.AddedMods.Select( mod => string.Format ("New mod: {0} {1}", mod.Name, mod.Version) )); items.AddRange(syncSummary.RemovedMods.Select( mod => string.Format ("Removed mod: {0}", mod.Name) )); if (syncSummary.NewConfiguration) items.Add("New configuration to download."); InstanceName = instance.Description.Name; Description = instance.Description.Description; var newDesc = Instance.FetchServerInstanceDescription(); serverNews.Buffer.Text = newDesc.MessageOfTheDay; //playButton.ImagePosition = PositionType.Left; if (items.Count > 0) { UpdateSummary = string.Join("\n", items.Select (x => " * "+x)); playButton.Image = Image.NewFromIconName(Stock.GoUp, IconSize.Button); playButton.Label = "Update to Play!"; } else { UpdateSummary = "None, ready to play!"; playButton.Hide(); playButton.Unrealize(); playButton.Label = "Play!"; playButton.Image = Image.NewFromIconName(Stock.Apply, IconSize.Button); playButton.Show(); } }
/// <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; } }
/// <summary> /// Create and construct Minecraft Command /// </summary> /// <returns>Status of exceptions or success</returns> private string FormatArguments(MinecraftSession session) { string mcNatives = string.Format ("-Djava.library.path=\"{0}\"", Path.Combine (GameLocation, "bin", "natives")); // Add -cp arguments for all non-extracted jar libs that we need List<string> mcLibraryEntries = new List<string>(); // Include libraries in java library path var jarLibs = VersionParameters.Libraries.Where (x => x.AppliesHere).Where (x => x.Extract == null); foreach (var lib in jarLibs) mcLibraryEntries.Add (string.Format ("{0}", Path.Combine (GameLocation, "bin", lib.JarName))); mcLibraryEntries.Add (JarFile); string mcLibraries = "-cp \""+string.Join(Path.PathSeparator.ToString(), mcLibraryEntries.ToArray())+"\""; // Determine the path for the Minecraft jar string mcClass = VersionParameters.MainClass; string mcArgs = VersionParameters.Arguments; mcArgs = mcArgs.Replace("${auth_player_name}", session.Username); string accountType = "legacy"; if (AccountType == MinecraftAccountType.Mojang) accountType = "mojang"; string authSession = "OFFLINE_MODE"; string authUUID = "OFFLINE_MODE"; string authAccessToken = "OFFLINE_MODE"; if (OnlineMode) { authSession = "token:" + session.AccessToken + ":" + session.ProfileId; authUUID = session.ProfileId; authAccessToken = session.AccessToken; } mcArgs = mcArgs.Replace("${auth_session}", authSession); mcArgs = mcArgs.Replace("${auth_uuid}", authUUID); mcArgs = mcArgs.Replace("${auth_access_token}", authAccessToken); string assetsDir = AssetsLocation; var manifest = AssetManifest; if (manifest.Virtual) assetsDir = Path.Combine(assetsDir, "legacy", "virtual"); mcArgs = mcArgs.Replace("${version_name}", SelectedVersion); mcArgs = mcArgs.Replace("${game_directory}", string.Format ("\"{0}\"", GameLocation)); mcArgs = mcArgs.Replace("${game_assets}", string.Format ("\"{0}\"", assetsDir)); mcArgs = mcArgs.Replace("${assets_root}", string.Format ("\"{0}\"", assetsDir)); mcArgs = mcArgs.Replace("${assets_index_name}", string.Format ("\"{0}\"", VersionParameters.Assets)); mcArgs = mcArgs.Replace("${user_properties}", "{}"); mcArgs = mcArgs.Replace("${user_type}", accountType); string additionalArgs = "-XX:PermSize=256M -Dfml.ignorePatchDiscrepancies=true -Dfml.ignoreInvalidMinecraftCertificates=true -Dfml.log.level=INFO"; return string.Format ("-Xms{0}M", StartRam) + " " + string.Format("-Xmx{0}M", MaxRam) + " " + additionalArgs + " " + mcNatives + " " + mcLibraries + " " + mcClass + " " + mcArgs; }
/// <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; }
public Process Start(MinecraftSession authSession) { return Start(authSession, new ConsoleGameProcessMonitor()); }
public void Login() { LoginDialog login = new LoginDialog (); SavedCredentials saved = null; string credsFileName = Path.Combine(Instance.GameFolder, "credentials.json"); if (File.Exists(credsFileName)) { using (var sr = new StreamReader(credsFileName)) saved = SavedCredentials.Parse(sr.ReadToEnd()); } if (saved != null) { login.Username = saved.AutoLoginUser; var savedCreds = saved.Credentials.Where(x => x.UserName == saved.AutoLoginUser).FirstOrDefault(); if (savedCreds != null) { login.Password = savedCreds.Password; login.RememberCredentials = true; } } while (true) { int response = login.Run (); if (response == (int)Gtk.ResponseType.Ok) { var auth = new MinecraftAuthentication (); string message = "Invalid login!"; try { Session = auth.Login (login.Username, login.Password); } catch (Exception e) { Session = null; message = e.Message; } if (Session == null || Session.AccessToken == null) { MessageBox (message); continue; } break; } else if (response == (int)Gtk.ResponseType.Cancel) { Gtk.Application.Quit(); Environment.Exit(0); } } saved = new SavedCredentials() { AutoLoginUser = login.Username, Credentials = new List<SavedCredential>() }; if (login.RememberCredentials) { saved.Credentials = new List<SavedCredential>() { new SavedCredential() { UserName = login.Username, Password = login.Password } }; } Directory.CreateDirectory(Path.GetDirectoryName(credsFileName)); using (StreamWriter sw = new StreamWriter(credsFileName)) sw.Write(saved.ToJson()); login.Hide (); login.Destroy(); }