public static HypixelSelf Deserialize(string dat)
        {
            JArray      json = JArray.Parse(dat);
            HypixelSelf self = new HypixelSelf();

            self.fakeFriends = new List <HypixelFriend>();
            foreach (JToken obj in json)
            {
                string UUID   = obj.Value <string>("UUID");
                string name   = obj.Value <string>("name");
                bool   loaded = bool.Parse(obj.Value <string>("loaded"));

                HypixelFriend f = new HypixelFriend(UUID);
                if (loaded)
                {
                    f.SetName(name);
                }

                self.fakeFriends.Add(f);
            }
            return(self);
        }
        private void LaunchButton_Click(object sender, EventArgs e)
        {
            string sptxt = Data.serverIP;

            if (!string.IsNullOrEmpty(sptxt))
            {
                File.WriteAllText("mars_client\\serverip.ser", sptxt);
            }
            else
            {
                File.WriteAllText("mars_client\\serverip.ser", "");
            }
            object _version = Data.versionString;

            if (_version == null)
            {
                MessageBox.Show("Please select a version!", "Mars", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
            string version = (string)_version;

            File.WriteAllText("mars_client\\version.ser", version);
            CMLauncher launcher = Data.launcher;
            bool       forge    = version.ToLower().Contains("forge");

            OutputManager.ShowConsoleWindow(true);
            Console.WriteLine("[MARS] Setting up launch arguments... Please wait!");

            MSession ssh;

            if (!Data.offline)
            {
                ssh = new MSession();
                Type editor = typeof(MSession);
                editor.GetField("<ClientToken>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(ssh, Data.clientToken);
                editor.GetField("<AccessToken>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(ssh, Data.accessToken);
                editor.GetField("<Username>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(ssh, Data.username);
                editor.GetField("<UUID>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(ssh, Data.mcUUID);
            }
            else
            {
                string username = Data.username;
                ssh = MSession.GetOfflineSession(username);
            }

            Console.WriteLine("[MARS] Successfully created session.");

            MLaunchOption options = new MLaunchOption()
            {
                JavaPath     = "java.exe",
                MaximumRamMb = GetInstalledMemoryMB() / 2,
                Session      = ssh,

                VersionType         = version,
                GameLauncherName    = "MarsClient",
                GameLauncherVersion = "1.5",
            };

            Console.WriteLine("[MARS] Assigned launch options.");

            if (forge)
            {
                string[] parts        = version.Split('-');
                string   mcVer        = parts[0];
                string   forgeVer     = parts[2] + "-" + parts[3];
                MProfile forgeProfile = launcher.GetProfile(mcVer, forgeVer);
                options.StartProfile = forgeProfile;
            }
            else
            {
                options.StartProfile = launcher.GetProfile(version);
            }
            if (!string.IsNullOrEmpty(sptxt))
            {
                options.ServerIp = sptxt;
            }

            Console.WriteLine("[MARS] Located target profile. Launching...");
            Console.WriteLine("[MARS] Moving to new thread...");

            Data.hook.OnHookKeyPressed += Hook_OnHookKeyPressed;
            MLaunch launch = new MLaunch(options);

            mcThread = new Thread(new ParameterizedThreadStart(delegate(object obj) {
                MLaunch threadLaunch       = (MLaunch)obj;
                Process pr                 = threadLaunch.GetProcess();
                ProcessStartInfo psi       = pr.StartInfo;
                psi.RedirectStandardOutput = true;
                psi.RedirectStandardInput  = true;
                psi.UseShellExecute        = false;
                staticMC = Process.Start(psi);
                staticMC.EnableRaisingEvents = true;

                launched         = true;
                staticMC.Exited += delegate
                {
                    //OutputManager.RemoveConsole();
                    rpcTimer.Stop();
                    Data.rpccli.Dispose();
                    Invoke((MethodInvoker) delegate
                    {
                        minecraftClosed = true;
                    });
                    mcThread.Abort();
                };
                staticMC.OutputDataReceived += (object _, DataReceivedEventArgs _a) =>
                {
                    string txt = _a.Data;
                    OutputManager.ProcessText(txt);
                    if (txt == null)
                    {
                        return;
                    }
                    if (txt.Contains("[Client thread/INFO]: Connecting to"))
                    {
                        int timeind      = txt.IndexOf(']');
                        string a         = txt.Substring(timeind + 38);
                        string b         = a.Split(',')[0];
                        string newserver = "Server: " + b;
                        if (!currentServer.Equals(newserver))
                        {
                            Debug.WriteLine("Connected to: \"" + b + "\"");
                            Console.WriteLine("Connected to: \"" + b + "\"");
                        }
                        currentServer = "Server: " + b;
                    }
                };
                staticMC.BeginOutputReadLine();
            }));
            mcThread.Start(launch);

            int launchWaits = 0;

            while (staticMC == null)
            {
                launchWaits++;
                Console.WriteLine("[MARS] Waiting for process to launch... #{0}", launchWaits);
                Thread.Sleep(250);
            }

            Console.WriteLine("[MARS] Waiting for main window handle...");
            Data.mcProcess = staticMC;
            while (staticMC.MainWindowHandle == IntPtr.Zero)
            {
                Thread.Sleep(100);
            }
            Data.mcWindow = staticMC.MainWindowHandle;

            Console.WriteLine("\n\n[MARS] Got main window handle. Attaching UI framework...");
            Console.WriteLine("[MARS] Building window...\n\n");

            InGameWindow igw = new InGameWindow();

            Data.hud = igw;
            igw.Show();
            SetParent(igw.Handle, Data.mcWindow);
            igw.NowParented();

            Console.WriteLine("[MARS] Begun window message pump.");
            Console.WriteLine("[MARS] Fetching HypixelSelf info...");

            if (File.Exists("mars_client\\hypixelself.ser"))
            {
                Data.player = HypixelSelf.Deserialize(File.ReadAllText
                                                          ("mars_client\\hypixelself.ser"));
            }

            Console.WriteLine("[MARS] Loaded, if any.\n\n");

            Console.WriteLine("[MARS] Finished initialization.");
        }
        // Every call downloads friend info if not present.
        private void FriendUpdateTimer_Tick(object sender, EventArgs e)
        {
            if (Data.player == null)
            {
                return;
            }

            HypixelSelf   self = Data.player;
            HypixelFriend?_f   = self.GetNextNeededUsername();

            if (_f.HasValue)
            {
                // Fetch username from UUID.
                HypixelFriend f        = _f.Value;
                string        UUID     = f.UUID;
                JObject       items    = Post(PROFILEAPI, UUID);
                string        username = items["name"].ToString();

                string saved     = HEAD_PATH + UUID + ".png";
                string savedFull = HEAD_PATH + UUID + "_FULL.png";

                if (!File.Exists(saved))
                {
                    // Contains skin information encoded in Base64.
                    string infoB64 = items["properties"][0]["value"].ToString();
                    byte[] infoBytes = Convert.FromBase64String(infoB64);
                    string info = Encoding.Default.GetString(infoBytes);
                    JToken textures = JObject.Parse(info)["textures"];
                    Bitmap loadedSkin = null; bool hasSkin = true;
                    // SKIN field is missing if no skin.
                    try { string _ = textures["SKIN"].ToString(); }
                    catch (Exception) { hasSkin = false; }
                    if (hasSkin)
                    {
                        using (WebClient wc = new WebClient())
                        {
                            wc.DownloadFile(textures["SKIN"]["url"].ToString(), savedFull);
                            using (Image img = Image.FromFile(savedFull))
                            {
                                loadedSkin = new Bitmap(8, 8);
                                using (Graphics gr = Graphics.FromImage(loadedSkin))
                                {
                                    gr.DrawImage(img, 0, 0, new Rectangle
                                                     (8, 8, 8, 8), GraphicsUnit.Pixel);
                                }
                            }
                        }
                    }
                    else
                    {
                        // Just make it a black head.
                        loadedSkin = new Bitmap(8, 8);
                        using (var g = Graphics.FromImage(loadedSkin))
                            g.FillRectangle(Brushes.Black, 0, 0, 8, 8);
                    }

                    using (loadedSkin)
                        using (Bitmap temp = new Bitmap(loadedSkin))
                            temp.Save(saved);
                }

                f.SetName(username);
                self.SetNextNeededUsername(f);
                Console.WriteLine("[MARS] Fetched friend info for {0}. {1}/{2} done.",
                                  username, self.LoadedCount(), self.Count());
            }
        }