diff --git a/MonkeyLoader.GamePacks.ResoniteModLoader/ModConfiguration.cs b/MonkeyLoader.GamePacks.ResoniteModLoader/ModConfiguration.cs index 40e6816..839a543 100644 --- a/MonkeyLoader.GamePacks.ResoniteModLoader/ModConfiguration.cs +++ b/MonkeyLoader.GamePacks.ResoniteModLoader/ModConfiguration.cs @@ -267,16 +267,4 @@ public ModConfigurationDefinition(ResoniteModBase owner, Version configVersion, AutoSave = autoSaveConfig; } } - - /// - /// Represents an encountered while loading a mod's configuration file. - /// - public class ModConfigurationException : Exception - { - internal ModConfigurationException(string message) : base(message) - { } - - internal ModConfigurationException(string message, Exception innerException) : base(message, innerException) - { } - } } \ No newline at end of file diff --git a/MonkeyLoader.GamePacks.ResoniteModLoader/ModConfigurationDefinitionBuilder.cs b/MonkeyLoader.GamePacks.ResoniteModLoader/ModConfigurationDefinitionBuilder.cs index e82b6f0..e412d0e 100644 --- a/MonkeyLoader.GamePacks.ResoniteModLoader/ModConfigurationDefinitionBuilder.cs +++ b/MonkeyLoader.GamePacks.ResoniteModLoader/ModConfigurationDefinitionBuilder.cs @@ -3,6 +3,7 @@ using MonkeyLoader.Configuration; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; @@ -13,10 +14,14 @@ namespace ResoniteModLoader /// public class ModConfigurationDefinitionBuilder { - private static readonly Type _modConfigKeyType = typeof(ModConfigurationKey); private static readonly MethodInfo _addRangeComponentMethod = AccessTools.Method(typeof(ModConfigurationDefinitionBuilder), nameof(AddRangeComponent)); + private static readonly string[] _definitiveEnabledToggles = new[] { "enabled", "mod enabled", "mod_enabled", "is_enabled" }; + private static readonly string[] _indicativeEnabledToggles = new[] { "enabled" }; + private static readonly Type _modConfigKeyType = typeof(ModConfigurationKey); + private readonly HashSet _keys = new(); private readonly ResoniteModBase _owner; + private bool _autoSaveConfig = true; private Version _configVersion = new(1, 0, 0); @@ -88,6 +93,43 @@ internal void ProcessAttributes() .Do(ProcessField); } + internal bool TryGetEnabledToggle([NotNullWhen(true)] out DefiningConfigKey? enabledToggleKey, bool remove = true) + { + enabledToggleKey = null; + ModConfigurationKey? enabledToggle = null; + + var potentialKeys = _keys.OfType>().ToArray(); + + foreach (var definitiveEnabledToggle in _definitiveEnabledToggles) + { + if (potentialKeys.FirstOrDefault(key => key.Name.Equals(definitiveEnabledToggle, StringComparison.OrdinalIgnoreCase)) is ModConfigurationKey enabledKey) + { + enabledToggle = enabledKey; + break; + } + } + + if (enabledToggle is null) + { + potentialKeys = potentialKeys + .Where(key => _indicativeEnabledToggles + .Any(name => key.Name.Contains(name, StringComparison.OrdinalIgnoreCase))) + .ToArray(); + + if (potentialKeys.Length != 1) + return false; + + enabledToggle = potentialKeys[0]; + } + + enabledToggleKey = (DefiningConfigKey)enabledToggle.UntypedKey; + + if (remove) + _keys.Remove(enabledToggle); + + return true; + } + private static void AddRangeComponent(DefiningConfigKey key, T min, T max) { var rangeComponent = new ConfigKeyRange(min, max, null); diff --git a/MonkeyLoader.GamePacks.ResoniteModLoader/ModConfigurationException.cs b/MonkeyLoader.GamePacks.ResoniteModLoader/ModConfigurationException.cs new file mode 100644 index 0000000..7ada1cb --- /dev/null +++ b/MonkeyLoader.GamePacks.ResoniteModLoader/ModConfigurationException.cs @@ -0,0 +1,16 @@ +using System; + +namespace ResoniteModLoader +{ + /// + /// Represents an encountered while loading a mod's configuration file. + /// + public class ModConfigurationException : Exception + { + internal ModConfigurationException(string message) : base(message) + { } + + internal ModConfigurationException(string message, Exception innerException) : base(message, innerException) + { } + } +} \ No newline at end of file diff --git a/MonkeyLoader.GamePacks.ResoniteModLoader/ModLoader.cs b/MonkeyLoader.GamePacks.ResoniteModLoader/ModLoader.cs index 7be0ab4..d8f0add 100644 --- a/MonkeyLoader.GamePacks.ResoniteModLoader/ModLoader.cs +++ b/MonkeyLoader.GamePacks.ResoniteModLoader/ModLoader.cs @@ -35,8 +35,9 @@ public sealed class ModLoader : ResoniteMonkey private static readonly Lazy _isHeadless = new(() => AccessTools.AllTypes().Any(type => type.Namespace == "FrooxEngine.Headless")); /// - /// Returns true if ResoniteModLoader was loaded by a headless + /// Gets whether this is running on a headless client. /// + /// true if ResoniteModLoader was loaded by a headless; otherwise, false. public static bool IsHeadless => _isHeadless.Value; /// diff --git a/MonkeyLoader.GamePacks.ResoniteModLoader/ResoniteMod.cs b/MonkeyLoader.GamePacks.ResoniteModLoader/ResoniteMod.cs index 0a18a0d..0597e52 100644 --- a/MonkeyLoader.GamePacks.ResoniteModLoader/ResoniteMod.cs +++ b/MonkeyLoader.GamePacks.ResoniteModLoader/ResoniteMod.cs @@ -1,4 +1,5 @@ using MonkeyLoader; +using MonkeyLoader.Configuration; using MonkeyLoader.Logging; using MonkeyLoader.Patching; using MonkeyLoader.Resonite; @@ -18,6 +19,11 @@ public abstract class ResoniteMod : ResoniteModBase { private readonly Lazy _configuration; + /// + /// Gets the Enabled-Toggle config item for this mod. + /// + internal DefiningConfigKey? EnabledToggle { get; private set; } + /// protected override ModConfiguration? Configuration => _configuration.Value; @@ -26,10 +32,10 @@ protected ResoniteMod() { _configuration = new(() => { - if (BuildConfigurationDefinition() is ModConfigurationDefinition definition) - return Config.LoadSection(new ModConfiguration(definition)); + if (BuildConfigurationDefinition() is not ModConfigurationDefinition definition) + return null; - return null; + return Config.LoadSection(new ModConfiguration(definition)); }); } @@ -186,6 +192,9 @@ internal static Logger GetLoggerFromStackTrace(StackTrace stackTrace) DefineConfiguration(builder); + if (builder.TryGetEnabledToggle(out var enabledToggleKey)) + EnabledToggle = enabledToggleKey; + return builder.Build(); } diff --git a/MonkeyLoader.GamePacks.ResoniteModLoader/RmlMod.cs b/MonkeyLoader.GamePacks.ResoniteModLoader/RmlMod.cs index 3244821..e8f83e4 100644 --- a/MonkeyLoader.GamePacks.ResoniteModLoader/RmlMod.cs +++ b/MonkeyLoader.GamePacks.ResoniteModLoader/RmlMod.cs @@ -18,17 +18,17 @@ namespace ResoniteModLoader { internal sealed class RmlMod : Mod { + /// + /// Map of Assembly to ResoniteMod, used for logging purposes + /// + internal static readonly Dictionary AssemblyLookupMap = new(); + private static readonly Type _resoniteModType = typeof(ResoniteMod); private static readonly Uri _rmlIconUrl = new("https://avatars.githubusercontent.com/u/145755526"); /// public override string Description => "RML Mods don't have descriptions."; - /// - /// Map of Assembly to ResoniteMod, used for logging purposes - /// - internal static readonly Dictionary AssemblyLookupMap = new(); - /// public override IFileSystem FileSystem { get; } @@ -79,6 +79,11 @@ public RmlMod(MonkeyLoader.MonkeyLoader loader, string? location, bool isGamePac authors.Add(resoniteMod.Author); monkeys.Add(resoniteMod); + resoniteMod.GetConfiguration(); + + if (resoniteMod.EnabledToggle is not null) + MonkeyToggles.A + // Add dependencies after refactoring MKL //foreach (var referencedAssembly in assembly.GetReferencedAssemblies()) // dependencies.Add(referencedAssembly.Name, new DependencyReference())