From 67f8f22a27879150d8fbe13c0a4126887babcc0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=AA=E5=9B=BD?= <61489151+AzusaSaku@users.noreply.github.com> Date: Tue, 30 Jun 2026 14:58:34 +0800 Subject: [PATCH] Avoid loading external plugins from the working directory by default Resolve relative plugin directories from the application base path and add CLI options for explicit plugin loading control. --- Cpp2IL.Core.Tests/Cpp2IlApiTests.cs | 17 +++++++++++++++++ Cpp2IL.Core/Cpp2IlApi.cs | 18 ++++++++++++++++-- Cpp2IL/CommandLineArgs.cs | 8 ++++++++ Cpp2IL/Program.cs | 5 ++++- README.md | 2 ++ 5 files changed, 47 insertions(+), 3 deletions(-) diff --git a/Cpp2IL.Core.Tests/Cpp2IlApiTests.cs b/Cpp2IL.Core.Tests/Cpp2IlApiTests.cs index 802f2424b..da782c058 100644 --- a/Cpp2IL.Core.Tests/Cpp2IlApiTests.cs +++ b/Cpp2IL.Core.Tests/Cpp2IlApiTests.cs @@ -8,4 +8,21 @@ public void UnityVersionIsCorrectlyDeterminedFromGlobalGameManagers() var version = Cpp2IlApi.DetermineUnityVersion(null, Paths.Simple2019Game.DataDirectory); Assert.That(version.Equals(2019, 4, 34)); } + + [Test] + public void RelativePluginDirectoryIsResolvedFromApplicationBaseDirectory() + { + var resolved = Cpp2IlApi.ResolvePluginDirectory("Plugins"); + var expected = System.IO.Path.GetFullPath(System.IO.Path.Combine(System.AppContext.BaseDirectory, "Plugins")); + + Assert.That(resolved, Is.EqualTo(expected)); + } + + [Test] + public void AbsolutePluginDirectoryIsUsedAsProvided() + { + var pluginDirectory = System.IO.Path.GetFullPath(System.IO.Path.Combine(System.IO.Path.GetTempPath(), "Cpp2ILPlugins")); + + Assert.That(Cpp2IlApi.ResolvePluginDirectory(pluginDirectory), Is.EqualTo(pluginDirectory)); + } } diff --git a/Cpp2IL.Core/Cpp2IlApi.cs b/Cpp2IL.Core/Cpp2IlApi.cs index bba501afb..11930a229 100644 --- a/Cpp2IL.Core/Cpp2IlApi.cs +++ b/Cpp2IL.Core/Cpp2IlApi.cs @@ -25,12 +25,26 @@ public static class Cpp2IlApi internal static bool LowMemoryMode => RuntimeOptions?.LowMemoryMode ?? false; [RequiresUnreferencedCode("Plugins are loaded dynamically.")] - public static void Init(string pluginsDir = "Plugins") + public static void Init(string pluginsDir = "Plugins", bool loadExternalPlugins = true) { - Cpp2IlPluginManager.LoadFromDirectory(Path.Combine(Environment.CurrentDirectory, pluginsDir)); + if (loadExternalPlugins) + Cpp2IlPluginManager.LoadFromDirectory(ResolvePluginDirectory(pluginsDir)); + else + Logger.InfoNewline("External plugin loading disabled.", "Plugins"); + Cpp2IlPluginManager.InitAll(); } + internal static string ResolvePluginDirectory(string pluginsDir) + { + if (string.IsNullOrWhiteSpace(pluginsDir)) + pluginsDir = "Plugins"; + + return Path.GetFullPath(Path.IsPathRooted(pluginsDir) + ? pluginsDir + : Path.Combine(AppContext.BaseDirectory, pluginsDir)); + } + public static UnityVersion DetermineUnityVersion(string? unityPlayerPath, string? gameDataPath) => LibCpp2IlMain.DetermineUnityVersion(unityPlayerPath, gameDataPath); diff --git a/Cpp2IL/CommandLineArgs.cs b/Cpp2IL/CommandLineArgs.cs index ad87422ed..9251e4be2 100644 --- a/Cpp2IL/CommandLineArgs.cs +++ b/Cpp2IL/CommandLineArgs.cs @@ -26,6 +26,14 @@ public class CommandLineArgs [Option("force-unity-version", HelpText = "Override the unity version detection. Don't use unless you know what you're doing, and use in conjunction with the other force options.")] public string? ForcedUnityVersion { get; set; } + //Plugin options + + [Option("plugins-dir", HelpText = "Specify a directory to load external Cpp2IL plugins from. Relative paths are resolved from the Cpp2IL application directory.")] + public string? PluginsDir { get; set; } + + [Option("no-plugins", HelpText = "Disable loading external Cpp2IL plugins. Built-in plugins are still initialized.")] + public bool NoPlugins { get; set; } + //Processor options [Option("list-processors", HelpText = "List the available processing layers and exit.")] diff --git a/Cpp2IL/Program.cs b/Cpp2IL/Program.cs index c0ead6276..9077f6ca3 100644 --- a/Cpp2IL/Program.cs +++ b/Cpp2IL/Program.cs @@ -505,8 +505,11 @@ private static Cpp2IlRuntimeArgs GetRuntimeOptionsFromCommandLine(string[] comma ConsoleLogger.ShowVerbose = options.Verbose; + if (options.NoPlugins && !string.IsNullOrWhiteSpace(options.PluginsDir)) + throw new SoftException("--plugins-dir cannot be used together with --no-plugins"); + #pragma warning disable IL2026 // RequiresUnreferencedCode - Cpp2IlApi.Init(); + Cpp2IlApi.Init(options.PluginsDir ?? "Plugins", !options.NoPlugins); #pragma warning restore IL2026 if (options.ListProcessors) diff --git a/README.md b/README.md index 37d8d61b8..89de00375 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,8 @@ same argument as above but pass in the path to the APK, and cpp2il will extract | --game-path | C:\Path\To\Game | Specify the path to the game folder. Required. | | --exe-name | TestGame | Specify the name of the game's exe file in case auto detection fails (because there are other exe files in the game directory) | | --verbose | <None> | Log more information about what we are doing | +| --plugins-dir | C:\Path\To\Plugins | Specify a directory to load external Cpp2IL plugins from. Relative paths are resolved from the Cpp2IL application directory. Defaults to the Plugins directory there. | +| --no-plugins | <None> | Disable loading external Cpp2IL plugins. Built-in plugins are still initialized. | | --list-processors | <None> | List available processing layers, then exit. | | --use-processor | attributeinjector | Select a processing layer to use, which can change the raw data prior to outputting. This option can appear multiple times. | | --processor-config | key=value | Provide configuration options to the selected processing layers. These will be documented by the plugin which adds the processing layer. |