public KVPRadioBtn(KeyValuePair <string, string[]> kvp, int locX, int locY, PickForm parent) { InitializeComponent(); this.Text = kvp.Key; this.KVP = kvp; this.Location = new Point(locX, locY); this.parent = parent; }
public void Download(string dependencyString, bool backupOnOverwrite) { //Get version from dependency string Version v = FindMod(dependencyString); //Download dependencies Download(v.Dependencies.ToArray()); //If the mod is already installed and the installed version is not older than this one, return, don't install this version if (installedmods.ContainsKey(v.ParentMod.LongName) && !new VersionNumber(installedmods[v.ParentMod.LongName].VersionNumber).IsOlder(v.VersionNumber)) { return; } //If the mod is deprecated, prompt the user that it may not work and ask if they want to install anyway; return if result is no if (v.ParentMod.IsDeprecated && MessageBox.Show(string.Format("This mod ({0}) is deprecated and may not install and run properly. It is recommended that you find a newer mod instead. Do you want to continue with installing this mod?", v.DependencyString), "Deprecated Mod", MessageBoxButtons.YesNo) == DialogResult.No) { return; } //Path to download folder string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "downloads"); //If download folder doesn't exist, create it if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } //Download package zip path = Path.Combine(path, v.DependencyString); using (var client = new WebClient()) { Console.WriteLine("Downloading {0} ...", v.DependencyString); client.Proxy = null; WebRequest.DefaultWebProxy = null; client.DownloadFile(v.DownloadUrl, path + ".zip"); client.Dispose(); } //Extract package Console.WriteLine("Extracting {0} ...", v.DependencyString); if (Directory.Exists(path)) { Helper.DeleteDirectory(path); } ZipFile.ExtractToDirectory(path + ".zip", path); string workingdir = path; //Files to not worry about copying string[] excludedfiles = new string[] { "icon.png", "license.txt", "manifest.json", "readme.md", "instructions.txt", "license", "credits.txt", "icon.psd", "assetplus.xml", "changelog.md", "license.md" }; //Begin install List <string> fileList = new List <string>(); if (File.Exists(Path.Combine(workingdir, "rules.json"))) //Author defined rules { //Read rules file Console.WriteLine("Installing with author-defined rule set ..."); StreamReader sr = new StreamReader(File.OpenRead(Path.Combine(workingdir, "rules.json"))); Dictionary <string, string> dict = JsonConvert.DeserializeObject <Dictionary <string, string> >(sr.ReadToEnd()); sr.Close(); sr.Dispose(); //Work through each directory in package foreach (string p in Directory.GetDirectories(workingdir, "*", SearchOption.TopDirectoryOnly)) { string[] parr = p.Split('\\'); string work = Path.Combine(workingdir, parr[parr.Length - 1]); string[] modfiles = Directory.GetFiles(work, "*", SearchOption.AllDirectories); foreach (string modf in modfiles) { string s = modf.Substring(work.Length + 1); string t = ""; if (dict.ContainsKey(parr[parr.Length - 1])) { t = dict[parr[parr.Length - 1]]; } switch (t.ToLower()) { case "bepinex": // bep s = Path.Combine(ror2, "BepInEx", s); break; case "plugins": // bep/plugins s = Path.Combine(ror2, "BepInEx", "plugins", v.DependencyString, s); break; case "patchers": // bep/patchers s = Path.Combine(ror2, "BepInEx", "patchers", s); break; case "monomod": // bep/monomod s = Path.Combine(ror2, "BepInEx", "monomod", s); break; case "core": // bep/core s = Path.Combine(ror2, "BepInEx", "core", s); break; case "data": // ror2_data s = Path.Combine(ror2, "Risk of Rain 2_Data", s); break; case "language": // ror2_data/language s = Path.Combine(ror2, "Risk of Rain 2_Data", "language", s); break; case "en-us": // ror2_data/language/en s = Path.Combine(ror2, "Risk of Rain 2_Data", "language", "en", s); break; case "managed": // ror2_data/managed s = Path.Combine(ror2, "Risk of Rain 2_Data", "managed", s); break; default: //act as plugins s = Path.Combine(ror2, "BepInEx", "plugins", v.DependencyString, s); break; } VerifyPathToFile(s); if (backupOnOverwrite && File.Exists(modf)) { File.Move(s, s + ".bak"); } File.Copy(modf, s, true); fileList.Add(s); Console.WriteLine("\"{0}\" copied to \"{1}\"", modf, s); } } } else { // default rules SpecialCaseRules sc = null; foreach (SpecialCaseRules scr in this.Rules.SpecialCases) { if (sc != null) { break; } if (scr.UUIDS.Contains(v.ParentMod.UUID4)) { sc = scr; } } if (sc != null) { //special case List <string> ignore = new List <string>(); foreach (string st in excludedfiles) { ignore.Add(st.ToLower()); } //pick one if (sc.PickOneOfX) { foreach (KeyValuePair <string, string[]> kvp in sc.PickOptions) { ignore.Add(Path.Combine(workingdir, kvp.Value[0]).ToLower()); } KeyValuePair <string, string[]> k; using (var form = new PickForm(v.ParentMod.LongName, sc.PickOptions)) { DialogResult res = form.ShowDialog(); if (res == DialogResult.Cancel) { Console.WriteLine("Cancelling mod installation after options cancel ..."); //Directory.Delete(workingdir); Helper.DeleteDirectory(workingdir); return; } else if (res == DialogResult.OK) { k = form.SelectedKVP; string mod = Path.Combine(workingdir, k.Value[0]); string s = mod.Split('\\')[mod.Split('\\').Length - 1]; switch (k.Value[1].ToLower()) { case "plugins": s = Path.Combine(ror2, "BepInEx", "plugins", v.DependencyString, s); break; default: s = Path.Combine(ror2, "BepInEx", "plugins", v.DependencyString, s); break; } VerifyPathToFile(s); if (backupOnOverwrite && File.Exists(s)) { File.Move(s, s + ".bak"); } File.Copy(mod, s, true); fileList.Add(s); Console.WriteLine("{0} -> Selected {1}", v.ParentMod.LongName, k.Key); } else { Console.WriteLine("+\n+\n+\nidk wtf just happened here - options dialog should've only given a dialog result of ok or cancel\n+\n+\n+"); } } } //Folders foreach (string p in Directory.GetDirectories(workingdir, "*", SearchOption.TopDirectoryOnly)) { string[] parr = p.Split('\\'); string work = Path.Combine(workingdir, parr[parr.Length - 1]); string[] modfiles = Directory.GetFiles(work, "*", SearchOption.AllDirectories); foreach (string modf in modfiles) { if (ignore.Contains(modf.ToLower())) { continue; } string s = modf.Substring(work.Length + 1); string t = ""; if (sc.Folders.ContainsKey(parr[parr.Length - 1])) { t = sc.Folders[parr[parr.Length - 1]]; } switch (t.ToLower()) { case "base": s = Path.Combine(ror2, s); break; case "bepinex": // bep s = Path.Combine(ror2, "BepInEx", s); break; case "plugins": // bep/plugins s = Path.Combine(ror2, "BepInEx", "plugins", v.DependencyString, s); break; case "plugins\\TwitchIntegration": // bep/plugins/TwitchIntegration s = Path.Combine(ror2, "BepInEx", "plugins", "TwitchIntegration", s); break; case "patchers": // bep/patchers s = Path.Combine(ror2, "BepInEx", "patchers", s); break; case "monomod": // bep/monomod s = Path.Combine(ror2, "BepInEx", "monomod", s); break; case "core": // bep/core s = Path.Combine(ror2, "BepInEx", "core", s); break; case "data": // ror2_data s = Path.Combine(ror2, "Risk of Rain 2_Data", s); break; case "language": // ror2_data/language s = Path.Combine(ror2, "Risk of Rain 2_Data", "language", s); break; case "en-us": // ror2_data/language/en s = Path.Combine(ror2, "Risk of Rain 2_Data", "language", "en", s); break; case "managed": // ror2_data/managed s = Path.Combine(ror2, "Risk of Rain 2_Data", "managed", s); break; default: //act as plugins s = Path.Combine(ror2, "BepInEx", "plugins", v.DependencyString, s); break; } VerifyPathToFile(s); if (backupOnOverwrite && File.Exists(s)) { File.Move(s, s + ".bak"); } File.Copy(modf, s, true); fileList.Add(s); Console.WriteLine("\"{0}\" copied to \"{1}\"", modf, s); ignore.Add(modf.ToLower()); } } //Files foreach (string f in Directory.GetFiles(workingdir, "*", SearchOption.TopDirectoryOnly)) { string[] farr = f.Split('\\'); if (ignore.Contains(f.ToLower()) || ignore.Contains(farr[farr.Length - 1].ToLower())) { continue; } farr = farr[farr.Length - 1].Split('.'); string s = f.Substring(workingdir.Length + 1); string t = ""; if (sc.Files.ContainsKey("." + farr[farr.Length - 1])) { t = sc.Files["." + farr[farr.Length - 1]]; } switch (t.ToLower()) { case "plugins": s = Path.Combine(ror2, "BepInEx", "plugins", v.DependencyString, s); break; default: s = Path.Combine(ror2, "BepInEx", "plugins", v.DependencyString, s); break; } VerifyPathToFile(s); if (backupOnOverwrite && File.Exists(s)) { File.Move(s, s + ".bak"); } File.Copy(f, s, true); fileList.Add(s); Console.WriteLine("\"{0}\" copied to \"{1}\"", f, s); ignore.Add(f.ToLower()); } } else { //general rules Console.WriteLine("Installing with default ruleset ..."); //folder rules foreach (string p in Directory.GetDirectories(workingdir, "*", SearchOption.TopDirectoryOnly)) { string[] parr = p.Split('\\'); string work = Path.Combine(workingdir, parr[parr.Length - 1]); string[] modfiles = Directory.GetFiles(work, "*", SearchOption.AllDirectories); foreach (string modf in modfiles) { string s = modf.Substring(work.Length + 1); string t = ""; if (this.Rules.Folders.ContainsKey(parr[parr.Length - 1])) { t = this.Rules.Folders[parr[parr.Length - 1]]; } switch (t.ToLower()) { case "bepinex": // bep s = Path.Combine(ror2, "BepInEx", s); break; case "plugins": // bep/plugins s = Path.Combine(ror2, "BepInEx", "plugins", v.DependencyString, s); break; case "patchers": // bep/patchers s = Path.Combine(ror2, "BepInEx", "patchers", s); break; case "monomod": // bep/monomod s = Path.Combine(ror2, "BepInEx", "monomod", s); break; case "core": // bep/core s = Path.Combine(ror2, "BepInEx", "core", s); break; case "data": // ror2_data s = Path.Combine(ror2, "Risk of Rain 2_Data", s); break; case "language": // ror2_data/language s = Path.Combine(ror2, "Risk of Rain 2_Data", "language", s); break; case "en-us": // ror2_data/language/en s = Path.Combine(ror2, "Risk of Rain 2_Data", "language", "en", s); break; case "managed": // ror2_data/managed s = Path.Combine(ror2, "Risk of Rain 2_Data", "managed", s); break; default: //act as plugins s = Path.Combine(ror2, "BepInEx", "plugins", v.DependencyString, s); break; } VerifyPathToFile(s); if (backupOnOverwrite && File.Exists(s)) { File.Move(s, s + ".bak"); } File.Copy(modf, s, true); fileList.Add(s); Console.WriteLine("\"{0}\" copied to \"{1}\"", modf, s); } } // //file rules foreach (string f in Directory.GetFiles(workingdir, "*", SearchOption.TopDirectoryOnly)) { string[] farr = f.Split('\\'); if (excludedfiles.Contains(farr[farr.Length - 1].ToLower())) { continue; } farr = farr[farr.Length - 1].Split('.'); string s = f.Substring(workingdir.Length + 1); string t = ""; if (this.Rules.Files.ContainsKey("." + farr[farr.Length - 1])) { t = this.Rules.Files["." + farr[farr.Length - 1]]; } switch (t.ToLower()) { case "plugins": s = Path.Combine(ror2, "BepInEx", "plugins", v.DependencyString, s); break; default: s = Path.Combine(ror2, "BepInEx", "plugins", v.DependencyString, s); break; } VerifyPathToFile(s); if (backupOnOverwrite && File.Exists(s)) { File.Move(s, s + ".bak"); } File.Copy(f, s, true); fileList.Add(s); Console.WriteLine("\"{0}\" copied to \"{1}\"", f, s); } } } Helper.DeleteDirectory(workingdir); // //SeikoML should be replaced by SeikoMLCompatLayer MappedInstalledMod map = new MappedInstalledMod() { VersionNumber = v.VersionNumber.ToString(), Files = fileList.ToArray() }; this.installedmods.Add(v.ParentMod.LongName, map); if (File.Exists(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "installed.json"))) { File.Delete(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "installed.json")); } StreamWriter sw = new StreamWriter(File.Open(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "installed.json"), FileMode.OpenOrCreate)); sw.Write(JsonConvert.SerializeObject(this.installedmods, Formatting.Indented)); sw.Flush(); sw.Close(); sw.Dispose(); }