329 lines
13 KiB
C#
329 lines
13 KiB
C#
using GCMM.Properties;
|
|
using Microsoft.Win32;
|
|
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 = steamPath + @"\steamapps\libraryfolders.vdf";
|
|
else
|
|
return null;
|
|
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);
|
|
if (!match.Success)
|
|
continue;
|
|
string library = match.Groups[1].Value.Replace("\\\\", "\\");
|
|
library += @"\steamapps\common\";
|
|
if (GetExe(library + "Techblox") != null)
|
|
return library + "Techblox";
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public string SelectGameFolder()
|
|
{
|
|
var ofd = new OpenFileDialog();
|
|
ofd.Filter = "Techblox executable|Techblox.exe|Techblox Preview executable|TechbloxPreview.exe";
|
|
ofd.Title = "Game location";
|
|
ofd.InitialDirectory = steamPath + @"\steamapps\common\";
|
|
ofd.CheckFileExists = true;
|
|
ofd.ShowDialog();
|
|
if (string.IsNullOrWhiteSpace(ofd.FileName))
|
|
return null;
|
|
return Directory.GetParent(ofd.FileName).FullName;
|
|
}
|
|
|
|
public (string, int) AskForSteamLogin()
|
|
{
|
|
while (MessageBox.Show("Couid not find your Steam configuration to set launch options.\n\n" +
|
|
"Please make sure you are logged into Steam and click Retry or click Cancel to skip setting this up.",
|
|
"Steam config not found", MessageBoxButtons.RetryCancel) != DialogResult.Cancel)
|
|
{
|
|
var ret = GetSteamLocationAndUser();
|
|
if (ret != (null, 0))
|
|
return ret;
|
|
}
|
|
return (null, 0);
|
|
}
|
|
|
|
/// <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);
|
|
bool shouldMatch = false;
|
|
bool ret = false;
|
|
for (int i = 0; i < lines.Length; i++)
|
|
{
|
|
if (lines[i] == "\t\t\t\t\t\"1078000\"")
|
|
shouldMatch = true; //Found the game
|
|
else if(shouldMatch)
|
|
{
|
|
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] = enabledCommand;
|
|
else
|
|
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);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
public (string, int) GetSteamLocationAndUser()
|
|
{
|
|
if (Environment.OSVersion.Platform != PlatformID.Win32NT) return (null, 0);
|
|
using (var key = Registry.CurrentUser.OpenSubKey(@"Software\Valve\Steam\ActiveProcess"))
|
|
{
|
|
string path = (string)key?.GetValue("SteamClientDll");
|
|
path = path != null ? Directory.GetParent(path).FullName : null;
|
|
return (path, (int)(key?.GetValue("ActiveUser") ?? 0));
|
|
}
|
|
}
|
|
|
|
public void DetectConfigLocationAndAutoStart(string steamPath, ref int user)
|
|
{
|
|
string path = steamPath + @"\userdata";
|
|
if (user == 0)
|
|
{
|
|
var dirs = Directory.GetDirectories(path);
|
|
var goodPaths = (from dir in dirs
|
|
where File.Exists(dir + @"\config\localconfig.vdf")
|
|
select dir).ToArray();
|
|
if (goodPaths.Length != 1)
|
|
{
|
|
(_, user) = AskForSteamLogin();
|
|
path += user;
|
|
}
|
|
else
|
|
{
|
|
path = goodPaths[0];
|
|
user = int.Parse(Path.GetFileName(path));
|
|
}
|
|
}
|
|
else
|
|
path += "\\" + user;
|
|
path += @"\config\localconfig.vdf";
|
|
if (path != null && user != 0 && File.Exists(path))
|
|
{
|
|
Settings.Default.SteamUserID = user;
|
|
UpdateOrGetSteamConfigToAutoStart(true);
|
|
}
|
|
else
|
|
Settings.Default.AutoLaunch = false;
|
|
}
|
|
|
|
private (EventHandler, Task) CheckStartGame(string command)
|
|
{
|
|
var tcs = new TaskCompletionSource<object>();
|
|
return ((sender, e) =>
|
|
{
|
|
Action act = async () =>
|
|
{
|
|
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/");
|
|
EndWork(false);
|
|
tcs.SetResult(null);
|
|
};
|
|
if (InvokeRequired)
|
|
Invoke(act);
|
|
else
|
|
act();
|
|
}, 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()
|
|
{
|
|
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;
|
|
}
|
|
|
|
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);
|
|
unpatched.Enabled = false;
|
|
return true;
|
|
}
|
|
|
|
public void EndWork(bool desc = true)
|
|
{
|
|
working = false;
|
|
UpdateButton(playbtn, true);
|
|
UpdateButton(settingsbtn, true);
|
|
if (desc)
|
|
modlist_SelectedIndexChanged(modlist, null);
|
|
unpatched.Enabled = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Path must start with \
|
|
/// </summary>
|
|
/// <param name="path"></param>
|
|
/// <param name="gamepath"></param>
|
|
/// <returns></returns>
|
|
public string GamePath(string path, string gamepath = null)
|
|
{
|
|
return ((gamepath ?? Settings.Default.GamePath) + path).Replace('\\', Path.DirectorySeparatorChar);
|
|
}
|
|
|
|
public string GetExe(string path = null)
|
|
{
|
|
if (File.Exists(GamePath("\\Techblox.exe", path)))
|
|
return "Techblox.exe";
|
|
if (File.Exists(GamePath("\\TechbloxPreview.exe", path)))
|
|
return "TechbloxPreview.exe";
|
|
return null;
|
|
}
|
|
|
|
private bool CheckNoExe()
|
|
{
|
|
return CheckNoExe(out _);
|
|
}
|
|
|
|
private bool CheckNoExe(out string path)
|
|
{
|
|
path = GetExe();
|
|
if (path == null)
|
|
{
|
|
MessageBox.Show("Techblox not found! Set the correct path in Settings.");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public async Task<DateTime> GetLastGameUpdateTime()
|
|
{
|
|
/*using (var client = GetClient())
|
|
{
|
|
string html = await client.DownloadStringTaskAsync("https://api.steamcmd.net/v1/info/1078000");
|
|
var regex = new Regex("<i>timeupdated:</i>[^<]*<b>([^<]*)</b>");
|
|
var match = regex.Match(html);
|
|
if (!match.Success)
|
|
return default;
|
|
return new DateTime(1970, 1, 1).AddSeconds(long.Parse(match.Groups[1].Value));
|
|
}*/
|
|
//return new DateTime(2020, 12, 28);
|
|
return default;
|
|
}
|
|
}
|
|
}
|