mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-13 03:43:50 +02:00
* fix(.NET): Stop CheckGameRunning from force checking processes I'm not really sure what I was thinking when I did that the way I did; They are not supposed to force check if they're closed after the first time...That's what the monitor is for. * feat(.NET): Add optional child process culling, clean up applauncher Add an AppApi method to set applauncher settings Enabled/KillChildrenOnExit Refactor repeated applauncher event code, move into methods * refactor: Move the pug code for every tab into its own file * refactor: Add PoC mixins to settings.pug ^& add comments for navigation Some proof of concept replacements of the categories, switches and a radio group in the General settings seection. Also added comments for each header-separated section for marginally better navigation of the file. * refactor: Move the login page to its own file * fix(.NET): Correct wrong variable being set in SetAppLauncherSettings * fix(.NET): Remove redundant/exception causing process refresh in monitor * refactor(.NET): Allow launcher to be disabled; Disabled by default. * refactor: Change screenshot helper default to true * feat: Expose new app launcher settings, add new settings category Translation keys added/removed: + view.settings.advanced.advanced.app_launcher.header + view.settings.advanced.advanced.app_launcher.folder_tooltip + view.settings.advanced.advanced.app_launcher.enable + view.settings.advanced.advanced.app_launcher.auto_close - view.settings.advanced.advanced.auto_launch - view.settings.advanced.advanced.auto_launch_tooltip * Add GPU Fix and Udon Exception Logging options, unload favorites tab when not in use * Fix GPUFix typo * Fix GPUFix typo 1 * Add logging for AVPro streams without usharp videoplayer * Lint --------- Co-authored-by: Natsumi <cmcooper123@hotmail.com>
178 lines
5.6 KiB
C#
178 lines
5.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
|
|
namespace VRCX
|
|
{
|
|
/// <summary>
|
|
/// The class responsible for launching user-defined applications when VRChat opens/closes.
|
|
/// </summary>
|
|
public class AutoAppLaunchManager
|
|
{
|
|
public static AutoAppLaunchManager Instance { get; private set; }
|
|
public static readonly string VRChatProcessName = "VRChat";
|
|
|
|
public bool Enabled = false;
|
|
/// <summary> Whether or not to kill child processes when VRChat closes. </summary>
|
|
public bool KillChildrenOnExit = true;
|
|
public readonly string AppShortcutDirectory;
|
|
|
|
private DateTime startTime = DateTime.Now;
|
|
private Dictionary<string, Process> startedProcesses = new Dictionary<string, Process>();
|
|
private static readonly byte[] shortcutSignatureBytes = { 0x4C, 0x00, 0x00, 0x00 }; // signature for ShellLinkHeader\
|
|
|
|
static AutoAppLaunchManager()
|
|
{
|
|
Instance = new AutoAppLaunchManager();
|
|
}
|
|
|
|
public AutoAppLaunchManager()
|
|
{
|
|
AppShortcutDirectory = Path.Combine(Program.AppDataDirectory, "startup");
|
|
|
|
if (!Directory.Exists(AppShortcutDirectory))
|
|
{
|
|
Directory.CreateDirectory(AppShortcutDirectory);
|
|
}
|
|
|
|
ProcessMonitor.Instance.ProcessStarted += OnProcessStarted;
|
|
ProcessMonitor.Instance.ProcessExited += OnProcessExited;
|
|
}
|
|
|
|
private void OnProcessExited(MonitoredProcess monitoredProcess)
|
|
{
|
|
if (startedProcesses.Count == 0 || !monitoredProcess.HasName(VRChatProcessName))
|
|
return;
|
|
|
|
if (KillChildrenOnExit)
|
|
KillChildProcesses();
|
|
}
|
|
|
|
private void OnProcessStarted(MonitoredProcess monitoredProcess)
|
|
{
|
|
if (!Enabled || !monitoredProcess.HasName(VRChatProcessName) || monitoredProcess.Process.StartTime < startTime)
|
|
return;
|
|
|
|
if (KillChildrenOnExit)
|
|
KillChildProcesses();
|
|
|
|
var shortcutFiles = FindShortcutFiles(AppShortcutDirectory);
|
|
|
|
foreach (var file in shortcutFiles)
|
|
{
|
|
if (!IsChildProcessRunning(file))
|
|
{
|
|
StartChildProcess(file);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Kills all running child processes.
|
|
/// </summary>
|
|
internal void KillChildProcesses()
|
|
{
|
|
foreach (var pair in startedProcesses)
|
|
{
|
|
var process = pair.Value;
|
|
|
|
if (!process.HasExited)
|
|
process.Kill();
|
|
}
|
|
|
|
startedProcesses.Clear();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Starts a new child process.
|
|
/// </summary>
|
|
/// <param name="path">The path.</param>
|
|
internal void StartChildProcess(string path)
|
|
{
|
|
var process = Process.Start(path);
|
|
startedProcesses.Add(path, process);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the child processes list.
|
|
/// Removes any processes that have exited.
|
|
/// </summary>
|
|
internal void UpdateChildProcesses()
|
|
{
|
|
foreach (var pair in startedProcesses.ToList())
|
|
{
|
|
var process = pair.Value;
|
|
if (process.HasExited)
|
|
startedProcesses.Remove(pair.Key);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks to see if a given file matches a current running child process.
|
|
/// </summary>
|
|
/// <param name="path">The path.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if child process running; otherwise, <c>false</c>.
|
|
/// </returns>
|
|
internal bool IsChildProcessRunning(string path)
|
|
{
|
|
return startedProcesses.ContainsKey(path);
|
|
}
|
|
|
|
internal void Init()
|
|
{
|
|
// What are you lookin at?
|
|
}
|
|
|
|
internal void Exit()
|
|
{
|
|
Enabled = false;
|
|
|
|
KillChildProcesses();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds windows shortcut files in a given folder.
|
|
/// </summary>
|
|
/// <param name="folderPath">The folder path.</param>
|
|
/// <returns>An array of shortcut paths. If none, then empty.</returns>
|
|
private static string[] FindShortcutFiles(string folderPath)
|
|
{
|
|
DirectoryInfo directoryInfo = new DirectoryInfo(folderPath);
|
|
FileInfo[] files = directoryInfo.GetFiles();
|
|
List<string> ret = new List<string>();
|
|
|
|
foreach (FileInfo file in files)
|
|
{
|
|
if (IsShortcutFile(file.FullName))
|
|
{
|
|
ret.Add(file.FullName);
|
|
}
|
|
}
|
|
|
|
return ret.ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the specified file path is a shortcut by checking the file header.
|
|
/// </summary>
|
|
/// <param name="filePath">The file path.</param>
|
|
/// <returns><c>true</c> if the given file path is a shortcut, otherwise <c>false</c></returns>
|
|
private static bool IsShortcutFile(string filePath)
|
|
{
|
|
byte[] headerBytes = new byte[4];
|
|
using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
|
{
|
|
if (fileStream.Length >= 4)
|
|
{
|
|
fileStream.Read(headerBytes, 0, 4);
|
|
}
|
|
}
|
|
|
|
return headerBytes.SequenceEqual(shortcutSignatureBytes);
|
|
}
|
|
}
|
|
}
|