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 codetags/v1.3.0
@@ -22,8 +22,9 @@ namespace GCMM | |||
InitializeComponent(); | |||
} | |||
private Dictionary<string, ModInfo> mods = new Dictionary<string, ModInfo>(); | |||
private string defaultInfo = @" | |||
private readonly Dictionary<string, ModInfo> mods = new Dictionary<string, ModInfo>(); | |||
private readonly ModInfo gcipa = new ModInfo { Author = "modtainers", Name = "GCIPA" }; | |||
private const string defaultInfo = @" | |||
Gamecraft Mod Manager | |||
If you click on a mod it will show some info about it. The install instructions there are usually for manual installs. | |||
@@ -234,12 +235,13 @@ You may also want to verify the game's files by right clicking the game in Steam | |||
} | |||
} | |||
private void refreshbtn_Click(object sender, EventArgs e) | |||
private async void refreshbtn_Click(object sender, EventArgs e) | |||
{ | |||
CheckIfPatched(); | |||
CheckIfPatched(); //Set from placeholder | |||
var mods = GetInstalledMods(); | |||
GetAvailableMods(); | |||
await GetAvailableMods(); | |||
CheckUninstalledMods(mods); | |||
CheckIfPatched(); //Check after getting the available mods to show GCIPA updates | |||
} | |||
private void validatebtn_Click(object sender, EventArgs e) | |||
@@ -29,7 +29,12 @@ namespace GCMM | |||
string disposition = client.ResponseHeaders["Content-Disposition"]; | |||
string filename = disposition.Substring(disposition.IndexOf("filename=") + 10).Replace("\"", ""); | |||
if (filename.EndsWith(".dll")) | |||
File.Move(tmppath, plugins.FullName + Path.DirectorySeparatorChar + mod.Name + ".dll"); //Force mod name to make uninstalls & identifying easier | |||
{ | |||
string name = plugins.FullName + Path.DirectorySeparatorChar + mod.Name + ".dll"; //Force mod name to make uninstalls & identifying easier | |||
if (File.Exists(name)) | |||
File.Delete(name); | |||
File.Move(tmppath, name); | |||
} | |||
else if (filename.EndsWith(".zip")) | |||
{ | |||
bool pluginOnly = true; | |||
@@ -40,10 +40,23 @@ namespace GCMM | |||
{ //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 void GetAvailableMods() | |||
public async Task GetAvailableMods() | |||
{ | |||
bool preview = GetExe()?.Contains("Preview") ?? false; | |||
using (var client = GetClient()) | |||
@@ -58,13 +71,14 @@ namespace GCMM | |||
Author = sp[0].Trim(), | |||
Name = sp[1].Trim() | |||
}; | |||
if (await FetchModInfo(mod, preview)) //If it's actually a mod | |||
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) | |||
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()) | |||
@@ -108,13 +122,16 @@ namespace GCMM | |||
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(); | |||
try | |||
if (desc) | |||
{ | |||
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... | |||
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; | |||
} | |||
@@ -10,6 +10,7 @@ using System.Net; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using System.Windows.Forms; | |||
using System.Reflection; | |||
namespace GCMM | |||
{ | |||
@@ -29,6 +30,12 @@ namespace GCMM | |||
playbtn.Text = pnp; | |||
return GameState.NoPatcher; | |||
} | |||
if (gcipa.Updatable) | |||
{ | |||
status.Text = "Status: Patcher outdated\nClicking play will update it"; | |||
playbtn.Text = pnp; | |||
return GameState.OldPatcher; | |||
} | |||
string nopatch = "Status: Unpatched\nClicking Play patches it"; | |||
string gc = GetExe().Replace(".exe", ""); | |||
string backups = GamePath(@"\IPA\Backups\" + gc); | |||
@@ -71,31 +78,36 @@ namespace GCMM | |||
EndWork(false); | |||
return; | |||
case GameState.NoPatcher: | |||
case GameState.OldPatcher: | |||
{ | |||
if (MessageBox.Show("The patcher (GCIPA) is not found. It's necessary to load the mods. It will be downloaded from https://git.exmods.org/modtainers/GCIPA/releases and ran to patch the game. You can unpatch to run without mods at any time.", "Patcher download needed", MessageBoxButtons.OKCancel) | |||
== DialogResult.Cancel) | |||
if (MessageBox.Show((status == GameState.NoPatcher | |||
? "The patcher (GCIPA) is not found. It's necessary to load the mods." | |||
: "There is a patcher update available!" | |||
) + "\n\nIt will be downloaded from https://git.exmods.org/modtainers/GCIPA/releases and ran to patch the game. You can validate the game to restore the original game files or simply disable mods at any time.", | |||
"Patcher download needed", MessageBoxButtons.OKCancel) == DialogResult.Cancel) | |||
{ | |||
EndWork(); | |||
return; | |||
} | |||
string releases = "/api/v1/repos/modtainers/GCIPA/releases"; | |||
string url; | |||
this.status.Text = "Status: Patching..."; | |||
using (WebClient client = GetClient()) | |||
{ | |||
url = JArray.Parse(await client.DownloadStringTaskAsync(releases)).First["assets"].First["browser_download_url"].ToString(); | |||
string url = gcipa.DownloadURL; | |||
await client.DownloadFileTaskAsync(url, "IPA.zip"); | |||
using (var fs = new FileStream("IPA.zip", FileMode.Open)) | |||
using (var za = new ZipArchive(fs)) | |||
za.ExtractToDirectory(Settings.Default.GamePath, true); //Overwrite files that were left from a previous install of the patcher | |||
} | |||
} | |||
GetInstalledMods(); //Update patcher state, should be fine for this rare event | |||
status = CheckIfPatched(); | |||
break; | |||
} | |||
switch (status) | |||
{ | |||
case GameState.NoPatcher: //Make sure it actually worked | |||
case GameState.OldPatcher: | |||
EndWork(false); | |||
return; | |||
case GameState.Unpatched: | |||
@@ -132,6 +144,7 @@ namespace GCMM | |||
{ | |||
NotFound, | |||
NoPatcher, | |||
OldPatcher, | |||
Unpatched, | |||
Patched | |||
} | |||