bloxstrap/Bloxstrap/Watcher.cs
bluepilledgreat 49fd8eb2d2
Some checks are pending
CI (Debug) / build (push) Waiting to run
CI (Release) / build (push) Waiting to run
CI (Release) / release (push) Blocked by required conditions
CI (Release) / release-test (push) Blocked by required conditions
improve Watcher ctor macro exclusions
2025-03-15 14:35:09 +00:00

132 lines
4.0 KiB
C#

using Bloxstrap.AppData;
using Bloxstrap.Integrations;
using Bloxstrap.Models;
namespace Bloxstrap
{
public class Watcher : IDisposable
{
private readonly InterProcessLock _lock = new("Watcher");
private readonly WatcherData? _watcherData;
private readonly NotifyIconWrapper? _notifyIcon;
public readonly ActivityWatcher? ActivityWatcher;
public readonly DiscordRichPresence? RichPresence;
public Watcher()
{
const string LOG_IDENT = "Watcher";
if (!_lock.IsAcquired)
{
App.Logger.WriteLine(LOG_IDENT, "Watcher instance already exists");
return;
}
string? watcherDataArg = App.LaunchSettings.WatcherFlag.Data;
if (String.IsNullOrEmpty(watcherDataArg))
{
#if DEBUG
string path = new RobloxPlayerData().ExecutablePath;
using var gameClientProcess = Process.Start(path);
_watcherData = new() { ProcessId = gameClientProcess.Id };
#else
throw new Exception("Watcher data not specified");
#endif
}
else
{
_watcherData = JsonSerializer.Deserialize<WatcherData>(Encoding.UTF8.GetString(Convert.FromBase64String(watcherDataArg)));
}
if (_watcherData is null)
throw new Exception("Watcher data is invalid");
if (App.Settings.Prop.EnableActivityTracking)
{
ActivityWatcher = new(_watcherData.LogFile);
if (App.Settings.Prop.UseDisableAppPatch)
{
ActivityWatcher.OnAppClose += delegate
{
App.Logger.WriteLine(LOG_IDENT, "Received desktop app exit, closing Roblox");
using var process = Process.GetProcessById(_watcherData.ProcessId);
process.CloseMainWindow();
};
}
if (App.Settings.Prop.UseDiscordRichPresence)
RichPresence = new(ActivityWatcher);
}
_notifyIcon = new(this);
}
public void KillRobloxProcess() => CloseProcess(_watcherData!.ProcessId, true);
public void CloseProcess(int pid, bool force = false)
{
const string LOG_IDENT = "Watcher::CloseProcess";
try
{
using var process = Process.GetProcessById(pid);
App.Logger.WriteLine(LOG_IDENT, $"Killing process '{process.ProcessName}' (pid={pid}, force={force})");
if (process.HasExited)
{
App.Logger.WriteLine(LOG_IDENT, $"PID {pid} has already exited");
return;
}
if (force)
process.Kill();
else
process.CloseMainWindow();
}
catch (Exception ex)
{
App.Logger.WriteLine(LOG_IDENT, $"PID {pid} could not be closed");
App.Logger.WriteException(LOG_IDENT, ex);
}
}
public async Task Run()
{
if (!_lock.IsAcquired || _watcherData is null)
return;
ActivityWatcher?.Start();
while (Utilities.GetProcessesSafe().Any(x => x.Id == _watcherData.ProcessId))
await Task.Delay(1000);
if (_watcherData.AutoclosePids is not null)
{
foreach (int pid in _watcherData.AutoclosePids)
CloseProcess(pid);
}
if (App.LaunchSettings.TestModeFlag.Active)
Process.Start(Paths.Process, "-settings -testmode");
}
public void Dispose()
{
App.Logger.WriteLine("Watcher::Dispose", "Disposing Watcher");
_notifyIcon?.Dispose();
RichPresence?.Dispose();
GC.SuppressFinalize(this);
}
}
}