Files
Flyoobe/FlybyScript/Patcher/ScriptPatcher.cs
T
2024-10-30 21:33:40 +01:00

238 lines
8.3 KiB
C#

using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
/*
* Imported from my xd-AntiSpy app https://github.com/builtbybel/xd-AntiSpy
*/
namespace FlybyScript
{
public class ScriptPatcher
{
public string PlugID { get; set; }
public string PlugInfo { get; set; }
public string[] PlugCheck { get; set; }
public string[] PlugDo { get; set; }
public string[] PlugUndo { get; set; }
public string PlugCategory { get; set; }
private Logger logger;
public ScriptPatcher(Logger logger)
{
this.logger = logger;
}
public bool PlugCheckFeature()
{
bool isFeatureActive = true;
foreach (var command in PlugCheck)
{
if (!ExecuteCommandAndCheckResult(command))
{
isFeatureActive = false;
break;
}
}
logger.Log($"Feature '{PlugID}' is {(isFeatureActive ? "active" : "inactive")}", System.Drawing.Color.Black);
return isFeatureActive;
}
// PlugCheck Helper to execute commands and check the result
private bool ExecuteCommandAndCheckResult(string command)
{
try
{
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = $"/c {command}",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
}
};
process.Start();
process.WaitForExit();
// Read the output of the command
string output = process.StandardOutput.ReadToEnd();
// Check if output contains "1" (indicating active) or "0" (indicating inactive)
bool isActive = output.Contains("1");
// logger.Log($"Plugin executed successfully: {command}. Result: {(isActive ? "active" : "inactive")}", System.Drawing.Color.Black);
return isActive;
}
catch (Exception ex)
{
logger.Log($"Error executing plugin: {command}. Exception: {ex.Message}", System.Drawing.Color.Crimson);
return false;
}
}
public async void PlugDoFeature()
{
await ExecuteFeatureCommands(PlugDo);
}
public async void PlugUndoFeature()
{
await ExecuteFeatureCommands(PlugUndo);
}
private async Task ExecuteFeatureCommands(string[] commands)
{
foreach (var command in commands)
{
await ExecuteCommand(command);
}
}
private async Task ExecuteCommand(string command)
{
try
{
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = IsPowerShellCommand(command) ? "powershell.exe" : "cmd.exe",
Arguments = IsPowerShellCommand(command) ? $"-Command \"{command}\"" : $"/c \"{command}\"",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
}
};
// Event handler for handling output data
process.OutputDataReceived += (sender, e) =>
{
if (!string.IsNullOrEmpty(e.Data))
{
logger.Log($"Output: {e.Data}", System.Drawing.Color.Green);
}
};
// Event handler for handling error data
process.ErrorDataReceived += (sender, e) =>
{
if (!string.IsNullOrEmpty(e.Data))
{
logger.Log($"Error: {e.Data}", System.Drawing.Color.Crimson);
}
};
process.Start();
// Begin asynchronous reading of the output and error streams
process.BeginOutputReadLine();
process.BeginErrorReadLine();
// Wait for the process to exit
await process.WaitForExitAsync();
// Log command execution
logger.Log($"Plugin executed command: {command}", System.Drawing.Color.Green);
}
catch (Exception ex)
{
logger.Log($"Error executing plugin: {command}. Exception: {ex.Message}", System.Drawing.Color.Crimson);
}
}
// Determine if our command should be run with PowerShell
private bool IsPowerShellCommand(string command)
{
return command.StartsWith("powershell.exe") || command.Contains("Get-") || command.Contains("Set-");
}
// Get plugin information
public string GetPluginInformation()
{
return $"{PlugInfo.Replace("\\n", Environment.NewLine)}";
}
private static void AddToPluginCategory(TreeNodeCollection pluginCategory, TreeNode node, string category)
{
if (pluginCategory == null)
throw new ArgumentNullException(nameof(pluginCategory));
var existingCategory = pluginCategory.Cast<TreeNode>().FirstOrDefault(n => n.Text == category);
if (existingCategory == null)
{
existingCategory = new TreeNode(category)
{
// BackColor = System.Drawing.Color.LightBlue,
ForeColor = System.Drawing.Color.Black
};
pluginCategory.Add(existingCategory);
}
existingCategory.Nodes.Add(node);
}
public static async Task LoadPlugins(string pluginDirectory, TreeNodeCollection pluginCategory, Logger logger)
{
if (Directory.Exists(pluginDirectory))
{
var pluginFiles = Directory.GetFiles(pluginDirectory, "*.json");
foreach (var file in pluginFiles)
{
// Exclude JSON files of our DLL Plugins as they are loaded separately
if (Path.GetFileName(file).IndexOf("Plugin", StringComparison.OrdinalIgnoreCase) >= 0)
continue;
try
{
var json = File.ReadAllText(file);
var plugin = JsonConvert.DeserializeObject<ScriptPatcher>(json);
if (plugin != null)
{
plugin.logger = logger; // Set logger for the plugin
// Execute all commands for the plugin to check its feature
bool isActive = plugin.PlugCheckFeature();
var pluginNode = new TreeNode(plugin.PlugID)
{
ToolTipText = plugin.PlugInfo,
Checked = isActive,
Tag = plugin // Store plugin object in Tag property
};
// Add to the appropriate category
AddToPluginCategory(pluginCategory, pluginNode, plugin.PlugCategory);
}
}
catch (Exception ex)
{
logger.Log($"Error loading plugin from file '{file}': {ex.Message}", System.Drawing.Color.Crimson);
}
}
}
}
}
}
// Extension method to make WaitForExit async in ExecuteCommand
public static class ProcessExtensions
{
public static async Task WaitForExitAsync(this Process process)
{
var tcs = new TaskCompletionSource<bool>();
process.EnableRaisingEvents = true;
process.Exited += (sender, args) => tcs.TrySetResult(true);
await tcs.Task;
}
}