Fix DLL conflicts, support updating GCIPA

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
This commit is contained in:
Norbi Peti 2020-08-23 23:38:10 +02:00
parent f271028001
commit f522432208
4 changed files with 56 additions and 19 deletions

View file

@ -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)

View file

@ -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;

View file

@ -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,14 +122,17 @@ 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();
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)
catch (WebException)
{ //It returns a HTTP 500 if it doesn't exist...
}
}
return true;
}
}

View file

@ -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
}