Browse Source

Split into multiple files

Using a single partial class because why not
tags/v1.0.0
NorbiPeti 3 years ago
parent
commit
c709304daf
5 changed files with 277 additions and 205 deletions
  1. +3
    -205
      GCMM/MainForm.cs
  2. +61
    -0
      GCMM/MainModder.cs
  3. +98
    -0
      GCMM/MainPatcher.cs
  4. +97
    -0
      GCMM/MainUtils.cs
  5. +18
    -0
      GCMM/ModInfo.cs

+ 3
- 205
GCMM/MainForm.cs View File

@@ -1,6 +1,7 @@
using GCMM.Properties;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
@@ -21,6 +22,8 @@ namespace GCMM
InitializeComponent();
}

private Dictionary<string, ModInfo> mods = new Dictionary<string, ModInfo>();

private void Form1_Load(object sender, EventArgs e)
{
modlist.Items.Clear();
@@ -45,211 +48,6 @@ namespace GCMM
GetAvailableMods();
}

public void UpdateButton(Button button, bool enabled)
{
if (enabled)
{
button.ForeColor = Color.Lime;
button.FlatAppearance.MouseOverBackColor = Color.FromArgb(0, 40, 0);
button.FlatAppearance.MouseDownBackColor = Color.Green;
}
else
{
button.ForeColor = Color.Green;
button.FlatAppearance.MouseOverBackColor = Color.Black;
button.FlatAppearance.MouseDownBackColor = Color.Black;
}
}

public string GetGameFolder()
{
string libs;
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
libs = @"C:\Program Files (x86)\Steam\steamapps\libraryfolders.vdf";
else
return null;
foreach (var line in File.ReadAllLines(libs).Concat(new[] { @"C:\Program Files (x86)\Steam\" }))
{
var regex = new Regex("\\t\"\\d+\"\\t\\t\"(.+)\"");
var match = regex.Match(line);
if (!match.Success)
continue;
string library = match.Groups[1].Value.Replace("\\\\", "\\");
library += @"\steamapps\common\";
if (File.Exists(library + @"Gamecraft\Gamecraft.exe"))
return library + "Gamecraft";
if (File.Exists(library + @"RobocraftX\Gamecraft.exe"))
return library + "RobocraftX";
}
return libs;
}

public string SelectGameFolder()
{
var ofd = new OpenFileDialog();
ofd.Filter = "Gamecraft executable|Gamecraft.exe";
ofd.Title = "Game location";
ofd.InitialDirectory = @"C:\Program Files (x86)\Steam\steamapps\common\";
ofd.CheckFileExists = true;
ofd.ShowDialog();
if (string.IsNullOrWhiteSpace(ofd.FileName))
return null;
return Directory.GetParent(ofd.FileName).FullName;
}

public void GetInstalledMods()
{
foreach (var mod in Directory.GetFiles(Settings.Default.GamePath + @"\Plugins", "*.dll"))
{
try
{
var an = AssemblyName.GetAssemblyName(mod);
if (an.Name == "0Harmony") continue;
var item = new ListViewItem(new[] { an.Name, "", an.Version.ToString(), File.GetLastWriteTime(mod).ToString() }, modlist.Groups["installed"]);
item.Name = an.Name;
modlist.Items.Add(item);
}
catch (BadImageFormatException)
{ //Not a .NET assembly
}
}
}

public bool? CheckIfPatched()
{
if (!File.Exists(Settings.Default.GamePath + @"\IPA.exe"))
{
status.Text = "Status: Patcher missing\nClicking Play will install it";
return null;
}
string nopatch = "Status: Unpatched\nClicking Play patches it";
if (!Directory.Exists(Settings.Default.GamePath + @"\IPA\Backups\Gamecraft"))
{
status.Text = nopatch;
return false;
}
string backup = Directory.EnumerateDirectories(Settings.Default.GamePath + @"\IPA\Backups\Gamecraft").OrderByDescending(s => s).FirstOrDefault();
if (backup == null)
{
status.Text = nopatch;
return false;
}
if (File.GetLastWriteTime(Settings.Default.GamePath + @"\Gamecraft_Data\Managed\Assembly-CSharp.dll")
> //If the file was updated at least 2 minutes after patching
Directory.GetLastWriteTime(backup).AddMinutes(2))
{
status.Text = nopatch;
return false;
}
status.Text = "Status: Patched";
return true;
}

public async void PatchGame()
{
UpdateButton(playbtn, false);
UpdateButton(installbtn, false);
UpdateButton(uninstallbtn, false);
UpdateButton(settingsbtn, false);
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)
== DialogResult.Cancel)
return;
string releases = "/api/v1/repos/modtainers/GCIPA/releases";
string url;
this.status.Text = "Status: Patching...";
using (WebClient client = await GetClient())
{
url = JArray.Parse(await client.DownloadStringTaskAsync(releases)).First["assets"].First["browser_download_url"].ToString();
await client.DownloadFileTaskAsync(url, "IPA.zip");
ZipFile.ExtractToDirectory("IPA.zip", Settings.Default.GamePath);
}
}
bool? status = CheckIfPatched();
if (!status.HasValue) //Make sure it actually worked
return;
if (!status.Value)
{
var psi = new ProcessStartInfo(Settings.Default.GamePath + @"\IPA.exe", "Gamecraft.exe --nowait");
psi.UseShellExecute = false;
psi.RedirectStandardError = true;
psi.RedirectStandardOutput = true;
psi.WorkingDirectory = Settings.Default.GamePath;
psi.CreateNoWindow = true;
var process = Process.Start(psi);
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.EnableRaisingEvents = true;
modinfobox.Text = "";
DataReceivedEventHandler onoutput = (sender, e) =>
{
Invoke((Action)(() => modinfobox.Text += e.Data + Environment.NewLine));
};
process.OutputDataReceived += onoutput;
process.ErrorDataReceived += onoutput;
process.Exited += CheckStartGame;
}
else
CheckStartGame(null, null);
}

private void CheckStartGame(object sender, EventArgs e)
{
Action act = () =>
{
if ((sender as Process).ExitCode != 0)
{
status.Text = "Status: Patching failed";
return;
}
if (CheckIfPatched() ?? false)
Process.Start("steam://run/1078000/");
};
if (InvokeRequired)
Invoke(act);
}

public async void GetAvailableMods()
{
string reposURL = "/api/v1/repos/search?sort=updated&order=desc";
using (var client = await GetClient())
{
var obj = JObject.Parse(await client.DownloadStringTaskAsync(reposURL));
if (!(bool)obj["ok"]) return;
foreach (var repo in obj["data"])
{
string name = repo["name"].ToString();
if (modlist.Items.ContainsKey(name))
{
var item = modlist.Items[name];
var si = item.SubItems;
si[1] = new ListViewItem.ListViewSubItem(item, repo["owner"]["username"].ToString());
}
else
{
var item = new ListViewItem(new[] { name, repo["owner"]["username"].ToString(), "", ((DateTime)repo["updated_at"]).ToString() }, modlist.Groups["available"]);
item.Name = name;
modlist.Items.Add(item);
}
}
}
}

public async Task<WebClient> GetClient()
{
var client = new WebClient();
if (!Settings.Default.UseProxy)
client.Proxy = null;
client.Headers.Clear();
client.Headers[HttpRequestHeader.Accept] = "application/json";
/*client.Headers[HttpRequestHeader.Host] = "git.exmods.org";
var addr = (await Dns.GetHostAddressesAsync("git.exmods.org")).Where(ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).First();
client.BaseAddress = "https://" + addr;*/
client.BaseAddress = "https://git.exmods.org";
return client;
}

private void playbtn_Click(object sender, EventArgs e)
{
if (playbtn.ForeColor == Color.Green) return; //Disabled


+ 61
- 0
GCMM/MainModder.cs View File

@@ -0,0 +1,61 @@
using GCMM.Properties;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace GCMM
{
partial class MainForm
{

public void GetInstalledMods()
{
foreach (var mod in Directory.GetFiles(Settings.Default.GamePath + @"\Plugins", "*.dll"))
{
try
{
var an = AssemblyName.GetAssemblyName(mod);
if (an.Name == "0Harmony") continue;
var item = new ListViewItem(new[] { an.Name, "", an.Version.ToString(), File.GetLastWriteTime(mod).ToString() }, modlist.Groups["installed"]);
item.Name = an.Name;
modlist.Items.Add(item);
}
catch (BadImageFormatException)
{ //Not a .NET assembly
}
}
}

public async void GetAvailableMods()
{
string reposURL = "/api/v1/repos/search?sort=updated&order=desc";
using (var client = GetClient())
{
var obj = JObject.Parse(await client.DownloadStringTaskAsync(reposURL));
if (!(bool)obj["ok"]) return;
foreach (var repo in obj["data"])
{
string name = repo["name"].ToString();
if (modlist.Items.ContainsKey(name))
{
var item = modlist.Items[name];
var si = item.SubItems;
si[1] = new ListViewItem.ListViewSubItem(item, repo["owner"]["username"].ToString());
}
else
{
var item = new ListViewItem(new[] { name, repo["owner"]["username"].ToString(), "", ((DateTime)repo["updated_at"]).ToString() }, modlist.Groups["available"]);
item.Name = name;
modlist.Items.Add(item);
}
}
}
}
}
}

+ 98
- 0
GCMM/MainPatcher.cs View File

@@ -0,0 +1,98 @@
using GCMM.Properties;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Compression;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace GCMM
{
partial class MainForm
{

public bool? CheckIfPatched()
{
if (!File.Exists(Settings.Default.GamePath + @"\IPA.exe"))
{
status.Text = "Status: Patcher missing\nClicking Play will install it";
return null;
}
string nopatch = "Status: Unpatched\nClicking Play patches it";
if (!Directory.Exists(Settings.Default.GamePath + @"\IPA\Backups\Gamecraft"))
{
status.Text = nopatch;
return false;
}
string backup = Directory.EnumerateDirectories(Settings.Default.GamePath + @"\IPA\Backups\Gamecraft").OrderByDescending(s => s).FirstOrDefault();
if (backup == null)
{
status.Text = nopatch;
return false;
}
if (File.GetLastWriteTime(Settings.Default.GamePath + @"\Gamecraft_Data\Managed\Assembly-CSharp.dll")
> //If the file was updated at least 2 minutes after patching
Directory.GetLastWriteTime(backup).AddMinutes(2))
{
status.Text = nopatch;
return false;
}
status.Text = "Status: Patched";
return true;
}

public async void PatchGame()
{
UpdateButton(playbtn, false);
UpdateButton(installbtn, false);
UpdateButton(uninstallbtn, false);
UpdateButton(settingsbtn, false);
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)
== DialogResult.Cancel)
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();
await client.DownloadFileTaskAsync(url, "IPA.zip");
ZipFile.ExtractToDirectory("IPA.zip", Settings.Default.GamePath);
}
}
bool? status = CheckIfPatched();
if (!status.HasValue) //Make sure it actually worked
return;
if (!status.Value)
{
var psi = new ProcessStartInfo(Settings.Default.GamePath + @"\IPA.exe", "Gamecraft.exe --nowait");
psi.UseShellExecute = false;
psi.RedirectStandardError = true;
psi.RedirectStandardOutput = true;
psi.WorkingDirectory = Settings.Default.GamePath;
psi.CreateNoWindow = true;
var process = Process.Start(psi);
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.EnableRaisingEvents = true;
modinfobox.Text = "";
DataReceivedEventHandler onoutput = (sender, e) =>
{
Invoke((Action)(() => modinfobox.Text += e.Data + Environment.NewLine));
};
process.OutputDataReceived += onoutput;
process.ErrorDataReceived += onoutput;
process.Exited += CheckStartGame;
}
else
CheckStartGame(null, null);
}
}
}

+ 97
- 0
GCMM/MainUtils.cs View File

@@ -0,0 +1,97 @@
using GCMM.Properties;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace GCMM
{
partial class MainForm
{
public void UpdateButton(Button button, bool enabled)
{
if (enabled)
{
button.ForeColor = Color.Lime;
button.FlatAppearance.MouseOverBackColor = Color.FromArgb(0, 40, 0);
button.FlatAppearance.MouseDownBackColor = Color.Green;
}
else
{
button.ForeColor = Color.Green;
button.FlatAppearance.MouseOverBackColor = Color.Black;
button.FlatAppearance.MouseDownBackColor = Color.Black;
}
}

public string GetGameFolder()
{
string libs;
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
libs = @"C:\Program Files (x86)\Steam\steamapps\libraryfolders.vdf";
else
return null;
foreach (var line in File.ReadAllLines(libs).Concat(new[] { @"C:\Program Files (x86)\Steam\" }))
{
var regex = new Regex("\\t\"\\d+\"\\t\\t\"(.+)\"");
var match = regex.Match(line);
if (!match.Success)
continue;
string library = match.Groups[1].Value.Replace("\\\\", "\\");
library += @"\steamapps\common\";
if (File.Exists(library + @"Gamecraft\Gamecraft.exe"))
return library + "Gamecraft";
if (File.Exists(library + @"RobocraftX\Gamecraft.exe"))
return library + "RobocraftX";
}
return libs;
}

public string SelectGameFolder()
{
var ofd = new OpenFileDialog();
ofd.Filter = "Gamecraft executable|Gamecraft.exe";
ofd.Title = "Game location";
ofd.InitialDirectory = @"C:\Program Files (x86)\Steam\steamapps\common\";
ofd.CheckFileExists = true;
ofd.ShowDialog();
if (string.IsNullOrWhiteSpace(ofd.FileName))
return null;
return Directory.GetParent(ofd.FileName).FullName;
}

private void CheckStartGame(object sender, EventArgs e)
{
Action act = () =>
{
if ((sender as Process).ExitCode != 0)
{
status.Text = "Status: Patching failed";
return;
}
if (CheckIfPatched() ?? false)
Process.Start("steam://run/1078000/");
};
if (InvokeRequired)
Invoke(act);
}

public WebClient GetClient()
{
var client = new WebClient();
if (!Settings.Default.UseProxy)
client.Proxy = null;
client.Headers.Clear();
client.Headers[HttpRequestHeader.Accept] = "application/json";
client.BaseAddress = "https://git.exmods.org";
return client;
}
}
}

+ 18
- 0
GCMM/ModInfo.cs View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GCMM
{
class ModInfo
{
public string Name { get; set; }
public string Version { get; set; }
public string LatestVersion { get; set; }
public string Description { get; set; }
public string Author { get; set; }
public DateTime LastUpdated { get; set; }
}
}

Loading…
Cancel
Save