NorbiPeti
f522432208
If the mod consists of a dll then it failed to update it because it already existed Added support for updating GCIPA, using both the existing mod info fetching and the patcher downloading code
186 lines
7.9 KiB
C#
186 lines
7.9 KiB
C#
using GCMM.Properties;
|
|
using Newtonsoft.Json.Linq;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Reflection;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
|
|
namespace GCMM
|
|
{
|
|
partial class MainForm
|
|
{
|
|
|
|
public HashSet<string> GetInstalledMods()
|
|
{
|
|
bool disabled = false;
|
|
if (!Directory.Exists(GamePath("\\Plugins")))
|
|
if (Directory.Exists(GamePath("\\Plugins_Disabled")))
|
|
disabled = true;
|
|
else return new HashSet<string>();
|
|
var installed = new HashSet<string>();
|
|
foreach (var modPath in Directory.GetFiles(GamePath(disabled ? @"\Plugins_Disabled" : @"\Plugins"), "*.dll"))
|
|
{
|
|
try
|
|
{
|
|
var an = AssemblyName.GetAssemblyName(modPath);
|
|
if (an.Name == "0Harmony") continue;
|
|
//Use filename to avoid differences between repository & assembly name casing
|
|
var mod = new ModInfo { Name = Path.GetFileNameWithoutExtension(modPath), Version = an.Version, LastUpdated = File.GetLastWriteTime(modPath) };
|
|
AddUpdateModInList(mod);
|
|
installed.Add(mod.Name);
|
|
}
|
|
catch (BadImageFormatException)
|
|
{ //Not a .NET assembly
|
|
}
|
|
}
|
|
try
|
|
{
|
|
string ipath = GamePath("\\IPA.exe"); //Heh
|
|
if (File.Exists(ipath))
|
|
{
|
|
var an = AssemblyName.GetAssemblyName(ipath);
|
|
gcipa.Version = an.Version;
|
|
gcipa.LastUpdated = File.GetLastWriteTime(ipath);
|
|
}
|
|
}
|
|
catch (BadImageFormatException)
|
|
{ //Not a .NET assembly
|
|
}
|
|
return installed;
|
|
}
|
|
|
|
public async Task GetAvailableMods()
|
|
{
|
|
bool preview = GetExe()?.Contains("Preview") ?? false;
|
|
using (var client = GetClient())
|
|
{
|
|
string str = await client.DownloadStringTaskAsync("https://exmods.org/mods/modlist.tsv");
|
|
foreach (string line in str.Trim().Split('\n'))
|
|
{
|
|
var sp = line.Split('\t');
|
|
if (sp.Length < 2) continue;
|
|
var mod = new ModInfo
|
|
{
|
|
Author = sp[0].Trim(),
|
|
Name = sp[1].Trim()
|
|
};
|
|
if (await FetchModInfo(mod, preview, true)) //If it's actually a mod
|
|
AddUpdateModInList(mod);
|
|
}
|
|
}
|
|
await FetchModInfo(gcipa, preview, false);
|
|
}
|
|
|
|
public async Task<bool> FetchModInfo(ModInfo mod, bool preview, bool desc)
|
|
{
|
|
string repoURL = "/api/v1/repos/" + mod.Author + "/" + mod.Name + "/releases";
|
|
using (var client = GetClient())
|
|
{
|
|
var arr = JArray.Parse(await client.DownloadStringTaskAsync(repoURL));
|
|
var release = arr.FirstOrDefault(rel =>
|
|
{
|
|
if ((bool) rel["prerelease"] || (bool) rel["draft"])
|
|
return false;
|
|
var vs = rel["tag_name"].ToString();
|
|
int ind = vs.IndexOf('-');
|
|
if (ind != -1)
|
|
{
|
|
if (vs.Substring(ind + 1).Equals("preview", StringComparison.InvariantCultureIgnoreCase)
|
|
&& !preview)
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
if (release == null)
|
|
return false;
|
|
var verstr = release["tag_name"].ToString().Replace("v", "");
|
|
int index = verstr.IndexOf('-');
|
|
if (index != -1)
|
|
verstr = verstr.Substring(0, index);
|
|
|
|
JToken asset;
|
|
if (release["assets"].Count() == 1)
|
|
asset = release["assets"].First;
|
|
else
|
|
asset = release["assets"].FirstOrDefault(token =>
|
|
{
|
|
string name = token["name"].ToString();
|
|
return name == mod.Name + ".dll" || name == mod.Name + ".zip";
|
|
});
|
|
|
|
mod.DownloadURL = asset?["browser_download_url"]?.ToString();
|
|
mod.LastUpdated = (DateTime)release["published_at"];
|
|
|
|
var ver = verstr.Split('.').Select(str => int.Parse(str)).ToArray();
|
|
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
|
|
mod.LatestVersion = new Version(getver(0), getver(1), getver(2), getver(3));
|
|
mod.UpdateDetails = release["name"] + "\n\n" + release["body"].ToString();
|
|
if (desc)
|
|
{
|
|
try
|
|
{
|
|
var obj = JObject.Parse(await client.DownloadStringTaskAsync("/api/v1/repos/" + mod.Author + "/" + mod.Name + "/contents/README.md"));
|
|
mod.Description = Encoding.UTF8.GetString(Convert.FromBase64String(obj["content"].ToString()));
|
|
}
|
|
catch (WebException)
|
|
{ //It returns a HTTP 500 if it doesn't exist...
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public void AddUpdateModInList(ModInfo mod)
|
|
{
|
|
if (mods.ContainsKey(mod.Name) ^ modlist.Items.ContainsKey(mod.Name)) //The ListView's keys aren't case sensitive
|
|
throw new InvalidOperationException("The mod isn't present in one of the two places: " + mod.Name);
|
|
ListViewItem item;
|
|
if (modlist.Items.ContainsKey(mod.Name))
|
|
{
|
|
var omod = mods[mod.Name];
|
|
item = modlist.Items[mod.Name];
|
|
var items = item.SubItems;
|
|
omod.Author = mod.Author ?? omod.Author;
|
|
omod.Version = mod.Version ?? omod.Version; //If the object comes from the dictionary then it's directly modified (uninstall)
|
|
omod.LatestVersion = mod.LatestVersion ?? omod.LatestVersion;
|
|
omod.LastUpdated = mod.LastUpdated == default ? omod.LastUpdated : mod.LastUpdated;
|
|
omod.Description = mod.Description ?? omod.Description;
|
|
omod.DownloadURL = mod.DownloadURL ?? omod.DownloadURL;
|
|
omod.UpdateDetails = mod.UpdateDetails ?? omod.UpdateDetails;
|
|
items[1].Text = omod.Author ?? "";
|
|
items[2].Text = (omod.Version ?? omod.LatestVersion)?.ToString();
|
|
items[3].Text = omod.LastUpdated.ToString();
|
|
item.Group = omod.Installed ? modlist.Groups["installed"] : modlist.Groups["available"];
|
|
mod = omod;
|
|
}
|
|
else
|
|
{
|
|
mods.Add(mod.Name, mod);
|
|
item = new ListViewItem(new[] { mod.Name, mod.Author ?? "", (mod.Version ?? mod.LatestVersion)?.ToString() ?? "", mod.LastUpdated.ToString() }, modlist.Groups[mod.Installed ? "installed" : "available"]);
|
|
item.Name = mod.Name;
|
|
modlist.Items.Add(item);
|
|
}
|
|
if (mod.LatestVersion != null && mod.Version != null && mod.Version < mod.LatestVersion)
|
|
item.ForeColor = Color.Blue;
|
|
else
|
|
item.ForeColor = modlist.ForeColor;
|
|
}
|
|
|
|
public void CheckUninstalledMods(HashSet<string> installed)
|
|
{
|
|
foreach (string name in mods.Keys.Except(installed))
|
|
{
|
|
var mod = mods[name];
|
|
mod.Version = null;
|
|
AddUpdateModInList(mod);
|
|
}
|
|
}
|
|
}
|
|
}
|