TBMM/GCMM/MainUtils.cs

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