Techblox Mod Manager / Launcher
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

170 lines
7.3KB

  1. using GCMM.Properties;
  2. using Newtonsoft.Json.Linq;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Drawing;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Net;
  9. using System.Reflection;
  10. using System.Runtime.CompilerServices;
  11. using System.Text;
  12. using System.Threading.Tasks;
  13. using System.Windows.Forms;
  14. namespace GCMM
  15. {
  16. partial class MainForm
  17. {
  18. public HashSet<string> GetInstalledMods()
  19. {
  20. bool disabled = false;
  21. if (!Directory.Exists(GamePath("\\Plugins")))
  22. if (Directory.Exists(GamePath("\\Plugins_Disabled")))
  23. disabled = true;
  24. else return new HashSet<string>();
  25. var installed = new HashSet<string>();
  26. foreach (var modPath in Directory.GetFiles(GamePath(disabled ? @"\Plugins_Disabled" : @"\Plugins"), "*.dll"))
  27. {
  28. try
  29. {
  30. var an = AssemblyName.GetAssemblyName(modPath);
  31. if (an.Name == "0Harmony") continue;
  32. //Use filename to avoid differences between repository & assembly name casing
  33. var mod = new ModInfo { Name = Path.GetFileNameWithoutExtension(modPath), Version = an.Version, LastUpdated = File.GetLastWriteTime(modPath) };
  34. AddUpdateModInList(mod);
  35. installed.Add(mod.Name);
  36. }
  37. catch (BadImageFormatException)
  38. { //Not a .NET assembly
  39. }
  40. }
  41. return installed;
  42. }
  43. public async void GetAvailableMods()
  44. {
  45. bool preview = GetExe()?.Contains("Preview") ?? false;
  46. using (var client = GetClient())
  47. {
  48. string str = await client.DownloadStringTaskAsync("https://exmods.org/mods/modlist.tsv");
  49. foreach (string line in str.Trim().Split('\n'))
  50. {
  51. var sp = line.Split('\t');
  52. if (sp.Length < 2) continue;
  53. var mod = new ModInfo
  54. {
  55. Author = sp[0].Trim(),
  56. Name = sp[1].Trim()
  57. };
  58. if (await FetchModInfo(mod, preview)) //If it's actually a mod
  59. AddUpdateModInList(mod);
  60. }
  61. }
  62. }
  63. public async Task<bool> FetchModInfo(ModInfo mod, bool preview)
  64. {
  65. string repoURL = "/api/v1/repos/" + mod.Author + "/" + mod.Name + "/releases";
  66. using (var client = GetClient())
  67. {
  68. var arr = JArray.Parse(await client.DownloadStringTaskAsync(repoURL));
  69. var release = arr.FirstOrDefault(rel =>
  70. {
  71. if ((bool) rel["prerelease"] || (bool) rel["draft"])
  72. return false;
  73. var vs = rel["tag_name"].ToString();
  74. int ind = vs.IndexOf('-');
  75. if (ind != -1)
  76. {
  77. if (vs.Substring(ind + 1).Equals("preview", StringComparison.InvariantCultureIgnoreCase)
  78. && !preview)
  79. return false;
  80. }
  81. return true;
  82. });
  83. if (release == null)
  84. return false;
  85. var verstr = release["tag_name"].ToString().Replace("v", "");
  86. int index = verstr.IndexOf('-');
  87. if (index != -1)
  88. verstr = verstr.Substring(0, index);
  89. JToken asset;
  90. if (release["assets"].Count() == 1)
  91. asset = release["assets"].First;
  92. else
  93. asset = release["assets"].FirstOrDefault(token =>
  94. {
  95. string name = token["name"].ToString();
  96. return name == mod.Name + ".dll" || name == mod.Name + ".zip";
  97. });
  98. mod.DownloadURL = asset?["browser_download_url"]?.ToString();
  99. mod.LastUpdated = (DateTime)release["published_at"];
  100. var ver = verstr.Split('.').Select(str => int.Parse(str)).ToArray();
  101. int getver(byte i) => ver.Length > i ? ver[i] : 0; //By default it sets values not present to -1, but we need them to be 0
  102. mod.LatestVersion = new Version(getver(0), getver(1), getver(2), getver(3));
  103. mod.UpdateDetails = release["name"] + "\n\n" + release["body"].ToString();
  104. try
  105. {
  106. var obj = JObject.Parse(await client.DownloadStringTaskAsync("/api/v1/repos/" + mod.Author + "/" + mod.Name + "/contents/README.md"));
  107. mod.Description = Encoding.UTF8.GetString(Convert.FromBase64String(obj["content"].ToString()));
  108. }
  109. catch(WebException)
  110. { //It returns a HTTP 500 if it doesn't exist...
  111. }
  112. return true;
  113. }
  114. }
  115. public void AddUpdateModInList(ModInfo mod)
  116. {
  117. if (mods.ContainsKey(mod.Name) ^ modlist.Items.ContainsKey(mod.Name)) //The ListView's keys aren't case sensitive
  118. throw new InvalidOperationException("The mod isn't present in one of the two places: " + mod.Name);
  119. ListViewItem item;
  120. if (modlist.Items.ContainsKey(mod.Name))
  121. {
  122. var omod = mods[mod.Name];
  123. item = modlist.Items[mod.Name];
  124. var items = item.SubItems;
  125. omod.Author = mod.Author ?? omod.Author;
  126. omod.Version = mod.Version ?? omod.Version; //If the object comes from the dictionary then it's directly modified (uninstall)
  127. omod.LatestVersion = mod.LatestVersion ?? omod.LatestVersion;
  128. omod.LastUpdated = mod.LastUpdated == default ? omod.LastUpdated : mod.LastUpdated;
  129. omod.Description = mod.Description ?? omod.Description;
  130. omod.DownloadURL = mod.DownloadURL ?? omod.DownloadURL;
  131. omod.UpdateDetails = mod.UpdateDetails ?? omod.UpdateDetails;
  132. items[1].Text = omod.Author ?? "";
  133. items[2].Text = (omod.Version ?? omod.LatestVersion)?.ToString();
  134. items[3].Text = omod.LastUpdated.ToString();
  135. item.Group = omod.Installed ? modlist.Groups["installed"] : modlist.Groups["available"];
  136. mod = omod;
  137. }
  138. else
  139. {
  140. mods.Add(mod.Name, mod);
  141. item = new ListViewItem(new[] { mod.Name, mod.Author ?? "", (mod.Version ?? mod.LatestVersion)?.ToString() ?? "", mod.LastUpdated.ToString() }, modlist.Groups[mod.Installed ? "installed" : "available"]);
  142. item.Name = mod.Name;
  143. modlist.Items.Add(item);
  144. }
  145. if (mod.LatestVersion != null && mod.Version != null && mod.Version < mod.LatestVersion)
  146. item.ForeColor = Color.Blue;
  147. else
  148. item.ForeColor = modlist.ForeColor;
  149. }
  150. public void CheckUninstalledMods(HashSet<string> installed)
  151. {
  152. foreach (string name in mods.Keys.Except(installed))
  153. {
  154. var mod = mods[name];
  155. mod.Version = null;
  156. AddUpdateModInList(mod);
  157. }
  158. }
  159. }
  160. }