Installing works, buttons are disabled while working

This commit is contained in:
Norbi Peti 2020-06-17 15:08:22 +02:00
parent 61d4930682
commit b03b63294e
10 changed files with 226 additions and 24 deletions

View file

@ -17,6 +17,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -35,6 +36,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Update="modlist.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Properties\Settings.settings"> <None Update="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator> <Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput> <LastGenOutput>Settings.Designer.cs</LastGenOutput>

View file

@ -38,6 +38,7 @@
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
this.modlist = new System.Windows.Forms.ListView(); this.modlist = new System.Windows.Forms.ListView();
this.modName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.modName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.modAuthor = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.modVersion = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.modVersion = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.modTimestamp = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.modTimestamp = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.status = new System.Windows.Forms.Label(); this.status = new System.Windows.Forms.Label();
@ -46,7 +47,6 @@
this.modinfobox = new System.Windows.Forms.TextBox(); this.modinfobox = new System.Windows.Forms.TextBox();
this.playbtn = new System.Windows.Forms.Button(); this.playbtn = new System.Windows.Forms.Button();
this.settingsbtn = new System.Windows.Forms.Button(); this.settingsbtn = new System.Windows.Forms.Button();
this.modAuthor = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.SuspendLayout(); this.SuspendLayout();
// //
// modlist // modlist
@ -90,6 +90,11 @@
this.modName.Text = "Name"; this.modName.Text = "Name";
this.modName.Width = 148; this.modName.Width = 148;
// //
// modAuthor
//
this.modAuthor.Text = "Author";
this.modAuthor.Width = 142;
//
// modVersion // modVersion
// //
this.modVersion.Text = "Version"; this.modVersion.Text = "Version";
@ -126,6 +131,7 @@
this.installbtn.TabIndex = 2; this.installbtn.TabIndex = 2;
this.installbtn.Text = "Install mod"; this.installbtn.Text = "Install mod";
this.installbtn.UseVisualStyleBackColor = true; this.installbtn.UseVisualStyleBackColor = true;
this.installbtn.Click += new System.EventHandler(this.installbtn_Click);
// //
// uninstallbtn // uninstallbtn
// //
@ -186,11 +192,6 @@
this.settingsbtn.UseVisualStyleBackColor = true; this.settingsbtn.UseVisualStyleBackColor = true;
this.settingsbtn.Click += new System.EventHandler(this.settingsbtn_Click); this.settingsbtn.Click += new System.EventHandler(this.settingsbtn_Click);
// //
// modAuthor
//
this.modAuthor.Text = "Author";
this.modAuthor.Width = 142;
//
// MainForm // MainForm
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);

View file

@ -51,7 +51,9 @@ namespace GCMM
private void playbtn_Click(object sender, EventArgs e) private void playbtn_Click(object sender, EventArgs e)
{ {
if (playbtn.ForeColor == Color.Green) return; //Disabled if (playbtn.ForeColor == Color.Green) return; //Disabled
if (!BeginWork()) return;
PatchGame(); PatchGame();
EndWork();
} }
private void settingsbtn_Click(object sender, EventArgs e) private void settingsbtn_Click(object sender, EventArgs e)
@ -63,7 +65,51 @@ namespace GCMM
private void modlist_SelectedIndexChanged(object sender, EventArgs e) private void modlist_SelectedIndexChanged(object sender, EventArgs e)
{ {
if (working) return;
switch (modlist.SelectedItems.Count)
{
case 0:
modinfobox.Text = "";
UpdateButton(installbtn, false);
UpdateButton(uninstallbtn, false);
break;
case 1:
default:
installbtn.Text = "Install mod";
UpdateButton(installbtn, false);
UpdateButton(uninstallbtn, false);
foreach (ListViewItem item in modlist.SelectedItems)
{
var mod = mods[item.Name];
if (modlist.SelectedItems.Count == 1)
modinfobox.Text = mod.Description?.Replace("\n", Environment.NewLine);
else
modinfobox.Text = modlist.SelectedItems.Count + " mods selected";
if (mod.DownloadURL != null && !(mod.LatestVersion <= mod.Version))
{
UpdateButton(installbtn, true);
if (mod.Version != null)
installbtn.Text = "Update mod";
else
installbtn.Text = "Install mod";
}
if (mod.Version != null)
UpdateButton(uninstallbtn, true);
}
break;
}
}
private async void installbtn_Click(object sender, EventArgs e)
{
if (installbtn.ForeColor == Color.Green) return; //Disabled
if (!BeginWork()) return;
foreach (ListViewItem item in modlist.SelectedItems)
{
if (item.Group.Name == "installed") continue;
await InstallMod(mods[item.Name]);
}
EndWork();
} }
} }
} }

58
GCMM/MainModInstaller.cs Normal file
View file

@ -0,0 +1,58 @@
using GCMM.Properties;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace GCMM
{
partial class MainForm
{
public async Task InstallMod(ModInfo mod)
{
if (mod.DownloadURL == null) return;
if (!File.Exists(Settings.Default.GamePath + @"\Gamecraft.exe"))
{
MessageBox.Show("Gamecraft not found. Set the correct path in Settings.");
return;
}
var tmp = Directory.CreateDirectory("temp");
var plugins = Directory.CreateDirectory(Settings.Default.GamePath + @"\Plugins");
string tmppath = tmp.FullName + "\\" + mod.Name;
using (var client = GetClient())
{
await client.DownloadFileTaskAsync(mod.DownloadURL, tmppath);
string disposition = client.ResponseHeaders["Content-Disposition"];
string filename = disposition.Substring(disposition.IndexOf("filename=") + 10).Replace("\"", "");
if (filename.EndsWith(".dll"))
File.Move(tmppath, plugins.FullName + "\\" + filename);
else if (filename.EndsWith(".zip"))
{
bool pluginOnly = true;
using (var archive = ZipFile.OpenRead(tmppath))
{
foreach (var entry in archive.Entries)
{
if (entry.FullName == "Plugins/")
{
pluginOnly = false;
break;
}
}
archive.ExtractToDirectory(pluginOnly ? plugins.FullName : Settings.Default.GamePath, true);
}
}
else
{
MessageBox.Show("Don't know how to install file: " + filename);
return;
}
GetInstalledMods(); //Update list
}
}
}
}

View file

@ -5,7 +5,9 @@ using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
@ -23,7 +25,7 @@ namespace GCMM
{ {
var an = AssemblyName.GetAssemblyName(modPath); var an = AssemblyName.GetAssemblyName(modPath);
if (an.Name == "0Harmony") continue; if (an.Name == "0Harmony") continue;
AddUpdateModInList(new ModInfo { Name = an.Name, Version = an.Version.ToString(), LastUpdated = File.GetLastWriteTime(modPath) }); AddUpdateModInList(new ModInfo { Name = an.Name, Version = an.Version, LastUpdated = File.GetLastWriteTime(modPath) });
} }
catch (BadImageFormatException) catch (BadImageFormatException)
{ //Not a .NET assembly { //Not a .NET assembly
@ -33,7 +35,7 @@ namespace GCMM
public async void GetAvailableMods() public async void GetAvailableMods()
{ {
string reposURL = "/api/v1/repos/search?sort=updated&order=desc"; /*string reposURL = "/api/v1/repos/search?sort=updated&order=desc";
using (var client = GetClient()) using (var client = GetClient())
{ {
var obj = JObject.Parse(await client.DownloadStringTaskAsync(reposURL)); var obj = JObject.Parse(await client.DownloadStringTaskAsync(reposURL));
@ -49,6 +51,17 @@ namespace GCMM
if (await FetchModInfo(mod)) //If it's actually a mod if (await FetchModInfo(mod)) //If it's actually a mod
AddUpdateModInList(mod); AddUpdateModInList(mod);
} }
}*/
foreach (string line in File.ReadLines("modlist.txt"))
{
var sp = line.Split('\t');
var mod = new ModInfo
{
Author = sp[0],
Name = sp[1]
};
if (await FetchModInfo(mod)) //If it's actually a mod
AddUpdateModInList(mod);
} }
} }
@ -57,17 +70,25 @@ namespace GCMM
string repoURL = "/api/v1/repos/" + mod.Author + "/" + mod.Name + "/releases"; string repoURL = "/api/v1/repos/" + mod.Author + "/" + mod.Name + "/releases";
using (var client = GetClient()) using (var client = GetClient())
{ {
var obj = JArray.Parse(await client.DownloadStringTaskAsync(repoURL)); var arr = JArray.Parse(await client.DownloadStringTaskAsync(repoURL));
var release = obj.FirstOrDefault(rel => !(bool)rel["prerelease"] && !(bool)rel["draft"]); var release = arr.FirstOrDefault(rel => !(bool)rel["prerelease"] && !(bool)rel["draft"]);
if (release == null) if (release == null)
return false; return false;
else if (release["assets"].Count() == 1)
{
mod.DownloadURL = release["assets"].First["browser_download_url"].ToString(); mod.DownloadURL = release["assets"].First["browser_download_url"].ToString();
mod.LastUpdated = (DateTime)release["published_at"]; mod.LastUpdated = (DateTime)release["published_at"];
mod.LatestVersion = release["tag_name"].ToString().Replace("v", ""); var ver = release["tag_name"].ToString().Replace("v", "").Split('.').Select(str => int.Parse(str)).ToArray();
return true; 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));
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;
} }
} }
@ -84,8 +105,10 @@ namespace GCMM
omod.Version = mod.Version ?? omod.Version; omod.Version = mod.Version ?? omod.Version;
omod.LatestVersion = mod.LatestVersion ?? omod.LatestVersion; omod.LatestVersion = mod.LatestVersion ?? omod.LatestVersion;
omod.LastUpdated = mod.LastUpdated == default ? omod.LastUpdated : mod.LastUpdated; omod.LastUpdated = mod.LastUpdated == default ? omod.LastUpdated : mod.LastUpdated;
omod.Description = mod.Description ?? omod.Description;
omod.DownloadURL = mod.DownloadURL ?? omod.DownloadURL;
items[1].Text = omod.Author ?? ""; items[1].Text = omod.Author ?? "";
items[2].Text = omod.Version ?? omod.LatestVersion; items[2].Text = (omod.Version ?? omod.LatestVersion)?.ToString();
items[3].Text = omod.LastUpdated.ToString(); items[3].Text = omod.LastUpdated.ToString();
item.Group = omod.Installed ? modlist.Groups["installed"] : modlist.Groups["available"]; item.Group = omod.Installed ? modlist.Groups["installed"] : modlist.Groups["available"];
if (mod.Version != mod.LatestVersion) if (mod.Version != mod.LatestVersion)
@ -94,7 +117,7 @@ namespace GCMM
else else
{ {
mods.Add(mod.Name, mod); mods.Add(mod.Name, mod);
var item = new ListViewItem(new[] { mod.Name, mod.Author ?? "", mod.Version ?? mod.LatestVersion ?? "", mod.LastUpdated.ToString() }, modlist.Groups[mod.Installed ? "installed" : "available"]); var 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; item.Name = mod.Name;
modlist.Items.Add(item); modlist.Items.Add(item);
} }

View file

@ -15,7 +15,6 @@ namespace GCMM
{ {
partial class MainForm partial class MainForm
{ {
public bool? CheckIfPatched() public bool? CheckIfPatched()
{ {
if (!File.Exists(Settings.Default.GamePath + @"\IPA.exe")) if (!File.Exists(Settings.Default.GamePath + @"\IPA.exe"))
@ -48,10 +47,6 @@ namespace GCMM
public async void PatchGame() public async void PatchGame()
{ {
UpdateButton(playbtn, false);
UpdateButton(installbtn, false);
UpdateButton(uninstallbtn, false);
UpdateButton(settingsbtn, false);
if (!CheckIfPatched().HasValue) if (!CheckIfPatched().HasValue)
{ {
if (MessageBox.Show("The patcher (GCIPA) is not found. It will be downloaded from https://git.exmods.org/modtainers/GCIPA/releases and ran to patch the game.", "Patcher download needed", MessageBoxButtons.OKCancel) if (MessageBox.Show("The patcher (GCIPA) is not found. It will be downloaded from https://git.exmods.org/modtainers/GCIPA/releases and ran to patch the game.", "Patcher download needed", MessageBoxButtons.OKCancel)

View file

@ -93,5 +93,29 @@ namespace GCMM
client.BaseAddress = "https://git.exmods.org"; client.BaseAddress = "https://git.exmods.org";
return client; return client;
} }
private bool working = false;
/// <summary>
/// Some simple "locking", only allow one operation at a time
/// </summary>
/// <returns>Whether the work can begin</returns>
public bool BeginWork()
{
if (working) return false;
working = true;
UpdateButton(playbtn, false);
UpdateButton(installbtn, false);
UpdateButton(uninstallbtn, false);
UpdateButton(settingsbtn, false);
return true;
}
public void EndWork()
{
working = false;
UpdateButton(playbtn, true);
UpdateButton(settingsbtn, true);
modlist_SelectedIndexChanged(modlist, null);
}
} }
} }

View file

@ -12,8 +12,8 @@ namespace GCMM
/// <summary> /// <summary>
/// Can be null. /// Can be null.
/// </summary> /// </summary>
public string Version { get; set; } public Version Version { get; set; }
public string LatestVersion { get; set; } public Version LatestVersion { get; set; }
/// <summary> /// <summary>
/// Can be null. /// Can be null.
/// </summary> /// </summary>

View file

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GCMM
{
public static class ZipArchiveExtensions
{ //https://stackoverflow.com/a/14795752/2703239
public static void ExtractToDirectory(this ZipArchive archive, string destinationDirectoryName, bool overwrite)
{
if (!overwrite)
{
archive.ExtractToDirectory(destinationDirectoryName);
return;
}
DirectoryInfo di = Directory.CreateDirectory(destinationDirectoryName);
string destinationDirectoryFullPath = di.FullName;
foreach (ZipArchiveEntry file in archive.Entries)
{
string completeFileName = Path.GetFullPath(Path.Combine(destinationDirectoryFullPath, file.FullName));
if (!completeFileName.StartsWith(destinationDirectoryFullPath, StringComparison.OrdinalIgnoreCase))
{
throw new IOException("Trying to extract file outside of destination directory. See this link for more info: https://snyk.io/research/zip-slip-vulnerability");
}
if (file.Name == "")
{// Assuming Empty for Directory
Directory.CreateDirectory(Path.GetDirectoryName(completeFileName));
continue;
}
file.ExtractToFile(completeFileName, true);
}
}
}
}

9
GCMM/modlist.txt Normal file
View file

@ -0,0 +1,9 @@
NGnius GamecraftRichPresenceMod
SnakesOnAGame GamecraftScripting
NGnius Pixi
modtainers GamecraftModdingAPI
ExtraCommands extracommands
NorbiPeti GCDC
NorbiPeti GCMC
NorbiPeti BlockMod
NGnius leadercraft