Browse Source

Auto-patch and other fixes, add checks and a setting

Also, possibly fixed detecting the game in Steam's default library
tags/v1.4.0
NorbiPeti 3 years ago
parent
commit
c11758a427
5 changed files with 137 additions and 41 deletions
  1. +7
    -7
      GCMM/MainForm.cs
  2. +10
    -2
      GCMM/MainPatcher.cs
  3. +89
    -29
      GCMM/MainUtils.cs
  4. +16
    -3
      GCMM/SettingsForm.Designer.cs
  5. +15
    -0
      GCMM/SettingsForm.cs

+ 7
- 7
GCMM/MainForm.cs View File

@@ -31,21 +31,21 @@ namespace GCMM
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.
To get started, click on a mod and select Install mod. Most mods need GamecraftModdingAPI as well.
Then, simply click Play. This will first download and run the patcher (GCIPA) if needed.
If all goes well, after some time a modded Gamecraft should launch.
To get started, click on a mod and select Install mod. Most mods need GamecraftModdingAPI as well so it'll be installed.
Then launch Gamecraft: if you enabled auto-patching then you can use Steam but if you didn't then you must use the Play button.
This will first download and run the patcher (GCIPA) if needed. If all goes well, after some time a modded Gamecraft should launch.

After a Gamecraft update there's a good chance that mods will break. If this happens you may get errors when trying to start Gamecraft.
Until updated versions are released, use the ""Disable mods"" checkbox at the bottom to launch the game without mods.
If you enabled auto-patching you will get a warning about this.

You don't have to use the mod manager to run the game each time, though it will tell you about mod updates when they come.
However, you need to run it and click ""Patch & Play"" each time there's a Gamecraft update.
If you don't have auto-patching enabled then you will need to run the mod manager each time Gamecraft updates and click ""Patch & Play"".

Disclaimer:
This mod manager and the mods in the list are made by the ExMods developers. We are not associated with Freejam or Gamecraft. Modify Gamecraft at your own risk.

If you encounter an issue while any mods are installed, report it to us. If you think it's an issue with the game, test again with the ""Disable mods"" option checked before reporting to Freejam.
You may also want to verify the game's files by right clicking the game in Steam and choosing Properties, going to Local files and clicking Verify integrity of game files.
You may also want to verify the game's files by clicking on the Validate game button.
";

private async void Form1_Load(object sender, EventArgs e)
@@ -65,7 +65,7 @@ You may also want to verify the game's files by right clicking the game in Steam
mods.Clear(); //This method may get called twice when ran from the command line
UpdateButton(installbtn, false);
modinfobox.Text = defaultInfo;
var (steamPath, user) = GetSteamLocationAndUser(); //TODO: If user is 0 then start Steam
var (steamPath, user) = GetSteamLocationAndUser();
if (steamPath != null)
this.steamPath = steamPath;
else


+ 10
- 2
GCMM/MainPatcher.cs View File

@@ -78,6 +78,7 @@ namespace GCMM
{
Show();
retOpenedWindowShouldStay = stay;
TopMost = true; //It opens in the background otherwise - should be fine since it only shows for a couple seconds
}
}
var status = CheckIfPatched();
@@ -143,11 +144,18 @@ namespace GCMM
};
process.OutputDataReceived += onoutput;
process.ErrorDataReceived += onoutput;
process.Exited += CheckStartGame; //target-typed conditional expression - C# 9.0
var (handler, task) = CheckStartGame(command);
process.Exited += handler;
await task;
}
break;
case GameState.Patched:
CheckStartGame(command, null); //Command may be null but that's okay
{
//CheckStartGame(command)(null, null);
var (handler, task) = CheckStartGame(command);
handler(null, null);
await task;
}
break;
}
return retOpenedWindowShouldStay;


+ 89
- 29
GCMM/MainUtils.cs View File

@@ -33,13 +33,13 @@ namespace GCMM
}

public string GetGameFolder()
{ //TODO
{
string libs;
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
libs = Settings.Default.SteamUserID + @"\steamapps\libraryfolders.vdf"; //TODO: Not the Steam folder anymore!
libs = steamPath + @"\steamapps\libraryfolders.vdf";
else
return null;
foreach (var line in File.ReadAllLines(libs).Concat(new[] {@"C:\Program Files (x86)\Steam\"}))
foreach (var line in File.ReadAllLines(libs).Concat(new[] { "\t\"19\"\t\t\"" + steamPath + "\"" }))
{
var regex = new Regex("\\t\"\\d+\"\\t\\t\"(.+)\"");
var match = regex.Match(line);
@@ -60,7 +60,7 @@ namespace GCMM
var ofd = new OpenFileDialog();
ofd.Filter = "Gamecraft executable|Gamecraft.exe|Gamecraft Preview executable|GamecraftPreview.exe";
ofd.Title = "Game location";
ofd.InitialDirectory = @"C:\Program Files (x86)\Steam\steamapps\common\"; //TODO
ofd.InitialDirectory = steamPath + @"\steamapps\common\";
ofd.CheckFileExists = true;
ofd.ShowDialog();
if (string.IsNullOrWhiteSpace(ofd.FileName))
@@ -81,8 +81,26 @@ namespace GCMM
return (null, 0);
}

private bool UpdateOrGetSteamConfigToAutoStart(bool? autoLaunch)
/// <summary>
/// Does not return the current value if setting it is not possible because Steam is running.
/// </summary>
/// <param name="autoLaunch">The value to set or null to keep as is</param>
/// <returns>The current value, unless setting it while Steam is running</returns>
public bool UpdateOrGetSteamConfigToAutoStart(bool? autoLaunch)
{
string commandToUse = Application.ExecutablePath + " -start %command%";
if (autoLaunch.HasValue && Process.GetProcessesByName("steam").Length > 0)
{ //Setting it while Steam is running
if (MessageBox.Show("Cannot set launch options while Steam is running." +
(autoLaunch.Value
? " Do you want to do it manually? If so, it will be copied on your clipboard." +
" Right click the game, select Properties and paste it in the launch options field."
: " Do you want to do it manually?" +
" If so, right click the game, select Properties and remove the text from the launch options field."),
"Launch options in Steam", MessageBoxButtons.YesNo) == DialogResult.Yes && autoLaunch.Value)
Clipboard.SetText(commandToUse);
return false;
}
var regex = new Regex(@"(\t{6}""LaunchOptions""\t+"")(.*)("")");
string path = steamPath + @"\userdata\" + Settings.Default.SteamUserID + @"\config\localconfig.vdf";
var lines = File.ReadAllLines(path);
@@ -97,22 +115,28 @@ namespace GCMM
var match = regex.Match(lines[i]);
if (!match.Success)
continue;
ret = match.Groups[2].Value.Contains("GCMM.exe");
string enabledCommand = match.Groups[1].Value + commandToUse.Replace("\\", "\\\\") + match.Groups[3].Value;
if (autoLaunch.HasValue)
{
if (autoLaunch.Value)
lines[i] = match.Groups[1].Value + Application.ExecutablePath + " -start %command%" + match.Groups[3].Value;
lines[i] = enabledCommand;
else
lines[i] = match.Groups[1].Value + match.Groups[2].Value;
lines[i] = match.Groups[1].Value + match.Groups[3].Value;
File.WriteAllLines(path, lines);
}
else if (ret && lines[i] != enabledCommand) //GCMM got moved or something and it's only queried, not set
{
lines[i] = enabledCommand;
File.WriteAllLines(path, lines);
}
ret = match.Groups[2].Value.Contains("GCMM.exe");
break;
}
}
return ret;
}

private (string, int) GetSteamLocationAndUser()
public (string, int) GetSteamLocationAndUser()
{
if (Environment.OSVersion.Platform != PlatformID.Win32NT) return (null, 0);
using (var key = Registry.CurrentUser.OpenSubKey(@"Software\Valve\Steam\ActiveProcess"))
@@ -123,7 +147,7 @@ namespace GCMM
}
}

private void DetectConfigLocationAndAutoStart(string steamPath, ref int user)
public void DetectConfigLocationAndAutoStart(string steamPath, ref int user)
{
string path = steamPath + @"\userdata";
if (user == 0)
@@ -155,28 +179,64 @@ namespace GCMM
Settings.Default.AutoLaunch = false;
}

private void CheckStartGame(object sender, EventArgs e)
private (EventHandler, Task) CheckStartGame(string command)
{
Action act = () =>
var tcs = new TaskCompletionSource<object>();
return ((sender, e) =>
{
if (((sender as Process)?.ExitCode ?? 0) != 0)
Action act = async () =>
{
status.Text = "Status: Patching failed";
return;
}
if (CheckIfPatched() == GameState.Patched || unpatched.Checked)
if (sender is string command)
Process.Start(command);
else if (Environment.OSVersion.Platform == PlatformID.Win32NT)
Process.Start("steam://run/1078000/");
else
Process.Start("xdg-open", "steam://run/1078000/");
};
if (InvokeRequired)
Invoke(act);
else
act();
EndWork(false);
if (((sender as Process)?.ExitCode ?? 0) != 0)
{
status.Text = "Status: Patching failed";
return;
}
if (CheckIfPatched() == GameState.Patched || unpatched.Checked)
if (command != null)
{
if (sender is Process) //Patched just now
CheckCompatibilityAndDisableMods();
await CheckModUpdatesAsync();
Process.Start(command);
}
else if (Environment.OSVersion.Platform == PlatformID.Win32NT)
Process.Start("steam://run/1078000/");
else
Process.Start("xdg-open", "steam://run/1078000/");
};
if (InvokeRequired)
Invoke(act);
else
act();
EndWork(false);
tcs.SetResult(null);
}, tcs.Task);
}

private void CheckCompatibilityAndDisableMods()
{
if (!unpatched.Checked && MessageBox.Show("If the game updated just now, some mods may be incompatible or they may work just fine." +
" Do you want to try running with mods?" +
"\n\nClick Yes to start the game with mods (after a small update or if you just installed GCMM)" +
"\nClick No to disable mods before starting the game (after a major update)" +
"\n\nYou can always enable/disable mods by launching GCMM.",
"Possible incompatibility warning", MessageBoxButtons.YesNo) == DialogResult.No)
unpatched.Checked = true;
}

private async Task CheckModUpdatesAsync()
{
var updatable = mods.Values.Where(mod => mod.Updatable).ToArray();
if (updatable.Length == 0)
return;
if (MessageBox.Show("Mod update(s) available!\n\n"
+ updatable.Select(mod => mod.Name + " " + mod.LatestVersion).Aggregate((a, b) => a + "\n")
+ "\n\nDo you want to update them now? You can also update later by opening GCMM.",
"Update(s) available", MessageBoxButtons.YesNo) == DialogResult.No)
return;
foreach (var mod in updatable)
await InstallMod(mod);
MessageBox.Show("Mods updated");
}

public WebClient GetClient()


+ 16
- 3
GCMM/SettingsForm.Designer.cs View File

@@ -35,6 +35,7 @@
this.savebtn = new System.Windows.Forms.Button();
this.cancelbtn = new System.Windows.Forms.Button();
this.useProxy = new System.Windows.Forms.CheckBox();
this.autopatching = new System.Windows.Forms.CheckBox();
this.SuspendLayout();
//
// label1
@@ -71,7 +72,7 @@
this.savebtn.FlatAppearance.MouseDownBackColor = System.Drawing.Color.Green;
this.savebtn.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(40)))), ((int)(((byte)(0)))));
this.savebtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.savebtn.Location = new System.Drawing.Point(271, 74);
this.savebtn.Location = new System.Drawing.Point(270, 113);
this.savebtn.Name = "savebtn";
this.savebtn.Size = new System.Drawing.Size(75, 23);
this.savebtn.TabIndex = 3;
@@ -85,7 +86,7 @@
this.cancelbtn.FlatAppearance.MouseDownBackColor = System.Drawing.Color.Green;
this.cancelbtn.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(40)))), ((int)(((byte)(0)))));
this.cancelbtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.cancelbtn.Location = new System.Drawing.Point(352, 74);
this.cancelbtn.Location = new System.Drawing.Point(352, 113);
this.cancelbtn.Name = "cancelbtn";
this.cancelbtn.Size = new System.Drawing.Size(75, 23);
this.cancelbtn.TabIndex = 4;
@@ -103,6 +104,16 @@
this.useProxy.Text = "Use system proxy settings";
this.useProxy.UseVisualStyleBackColor = true;
//
// autopatching
//
this.autopatching.AutoSize = true;
this.autopatching.Location = new System.Drawing.Point(12, 72);
this.autopatching.Name = "autopatching";
this.autopatching.Size = new System.Drawing.Size(194, 17);
this.autopatching.TabIndex = 6;
this.autopatching.Text = "Enable auto-patching on game start";
this.autopatching.UseVisualStyleBackColor = true;
//
// SettingsForm
//
this.AcceptButton = this.savebtn;
@@ -110,7 +121,8 @@
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.Black;
this.CancelButton = this.cancelbtn;
this.ClientSize = new System.Drawing.Size(439, 109);
this.ClientSize = new System.Drawing.Size(439, 148);
this.Controls.Add(this.autopatching);
this.Controls.Add(this.useProxy);
this.Controls.Add(this.cancelbtn);
this.Controls.Add(this.savebtn);
@@ -141,6 +153,7 @@
private System.Windows.Forms.Button savebtn;
private System.Windows.Forms.Button cancelbtn;
private System.Windows.Forms.CheckBox useProxy;
private System.Windows.Forms.CheckBox autopatching;
}
}


+ 15
- 0
GCMM/SettingsForm.cs View File

@@ -16,6 +16,7 @@ namespace GCMM
public partial class SettingsForm : Form
{
private MainForm mainForm;
private bool autopatchingEnabled;
public SettingsForm()
{
InitializeComponent();
@@ -26,6 +27,8 @@ namespace GCMM
gamelocation.Text = Settings.Default.GamePath;
useProxy.Checked = Settings.Default.UseProxy;
mainForm = Owner as MainForm;
autopatchingEnabled = Settings.Default.SteamUserID != 0 && mainForm.UpdateOrGetSteamConfigToAutoStart(null);
autopatching.Checked = autopatchingEnabled;
}

private void browsebtn_Click(object sender, EventArgs e)
@@ -37,6 +40,18 @@ namespace GCMM
{
Settings.Default.GamePath = gamelocation.Text;
Settings.Default.UseProxy = useProxy.Checked;
if (autopatching.Checked != autopatchingEnabled)
{
if (autopatching.Checked && Settings.Default.SteamUserID == 0)
{
var (steamPath, user) = mainForm.GetSteamLocationAndUser();
if (user != 0)
mainForm.DetectConfigLocationAndAutoStart(steamPath, ref user);
Settings.Default.SteamUserID = user; //If it's 0 then it's no change
}
else
mainForm.UpdateOrGetSteamConfigToAutoStart(autopatching.Checked);
}
Settings.Default.Save();
Close();
}


Loading…
Cancel
Save