Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ExponentialItemsReloaded v1.2.0
plugins\ExponentialItemsReloaded.dll
Decompiled 3 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExponentialItemsReloaded.Configuration; using ExponentialItemsReloaded.Content; using ExponentialItemsReloaded.Services; using HarmonyLib; using Microsoft.CodeAnalysis; using R2API; using RoR2; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ExponentialItemsReloaded")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ExponentialItemsReloaded")] [assembly: AssemblyTitle("ExponentialItemsReloaded")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ExponentialItemsReloaded { [BepInPlugin("CryptidLabs.ExponentialItemsReloaded", "ExponentialItemsReloaded", "1.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class ExponentialItemsReloadedPlugin : BaseUnityPlugin { internal const string PluginGUID = "CryptidLabs.ExponentialItemsReloaded"; internal const string R2APICoreGUID = "com.riskofthunder.r2api"; internal const string PluginName = "ExponentialItemsReloaded"; internal const string PluginVersion = "1.2.0"; private Harmony _harmony; internal static ExponentialItemsReloadedPlugin Instance { get; private set; } internal ModConfig PluginConfig { get; private set; } internal ItemConfigRegistry ItemCatalogSettings { get; private set; } internal ExponentialGrantEvaluator GrantEvaluator { get; private set; } private void Awake() { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown Instance = this; PluginConfig = new ModConfig(((BaseUnityPlugin)this).Config); ItemCatalogSettings = new ItemConfigRegistry(PluginConfig, ((BaseUnityPlugin)this).Logger); GrantEvaluator = new ExponentialGrantEvaluator(PluginConfig, ItemCatalogSettings, ((BaseUnityPlugin)this).Logger, () => ExponentArtifact.IsEnabledForCurrentRun()); ExponentArtifact.Register(((BaseUnityPlugin)this).Logger); HookRoR2Lifecycle(); PluginConfig.Bindings.SettingChanged += OnAnySettingChanged; _harmony = new Harmony("CryptidLabs.ExponentialItemsReloaded"); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"ExponentialItemsReloaded 1.2.0 loaded — awaiting ItemCatalog initialization for blacklist/override resolution."); } private void HookRoR2Lifecycle() { RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(HandleRoR2Loaded)); } private void OnDestroy() { RoR2Application.onLoad = (Action)Delegate.Remove(RoR2Application.onLoad, new Action(HandleRoR2Loaded)); if (PluginConfig != null) { PluginConfig.Bindings.SettingChanged -= OnAnySettingChanged; } Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } Instance = null; } private void HandleRoR2Loaded() { try { ItemCatalogSettings.RequestCatalogRebuild(); ItemCatalogSettings.RebuildCatalogCachesIfNeeded(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"RoR2 onLoad invoked — exponential filter dictionaries refreshed."); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Failed while rebuilding catalog caches after RoR2 load: {arg}"); } } private void OnAnySettingChanged(object sender, SettingChangedEventArgs e) { try { ItemCatalogSettings.RequestCatalogRebuild(); ItemCatalogSettings.RebuildCatalogCachesIfNeeded(); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Config refresh failed: {arg}"); } } } } namespace ExponentialItemsReloaded.Services { public sealed class ExponentialGrantEvaluator { private readonly ModConfig _config; private readonly ItemConfigRegistry _registry; private readonly ManualLogSource _log; private readonly Func<bool> _artifactActiveQuery; private bool _loggedLinearSanitize; public ExponentialGrantEvaluator(ModConfig config, ItemConfigRegistry registry, ManualLogSource log, Func<bool> artifactActiveQuery) { _config = config ?? throw new ArgumentNullException("config"); _registry = registry ?? throw new ArgumentNullException("registry"); _log = log ?? throw new ArgumentNullException("log"); _artifactActiveQuery = artifactActiveQuery ?? throw new ArgumentNullException("artifactActiveQuery"); } public int EvaluateAdjustedCount(Inventory inventory, ItemDef itemDef, int vanillaCount) { if (!NetworkServer.active) { return vanillaCount; } if (!_config.Enabled.Value) { return vanillaCount; } if (!Object.op_Implicit((Object)(object)inventory) || !Object.op_Implicit((Object)(object)itemDef)) { return Math.Max(vanillaCount, 0); } try { return EvaluateCore(inventory, itemDef, vanillaCount); } catch (Exception arg) { _log.LogError((object)$"Safeguard fallback while evaluating exponential pickup for {((itemDef != null) ? ((Object)itemDef).name : null)}: {arg}"); return Math.Max(vanillaCount, 0); } } private int EvaluateCore(Inventory inventory, ItemDef itemDef, int vanillaCount) { _registry.RebuildCatalogCachesIfNeeded(); int num = Math.Max(vanillaCount, 0); int itemCountEffective = inventory.GetItemCountEffective(itemDef); int globalCap = Math.Max(1, _config.GlobalMaxItemStacks.Value); int applicableMaxStacks = _registry.GetApplicableMaxStacks(itemDef, globalCap); int headroom = Math.Max(0, applicableMaxStacks - itemCountEffective); if (_config.RequireArtifact.Value && !_artifactActiveQuery()) { if (_config.VerboseLogging.Value) { _log.LogDebug((object)$"Artifact disabled — leaving vanilla grant x{num} for {((Object)itemDef).name}."); } return ClampToHeadroom(num, headroom); } if (!_registry.ShouldReceiveExponential(itemDef)) { if (_config.VerboseLogging.Value) { _log.LogDebug((object)$"Filter blocked exponentials for {((Object)itemDef).name}; vanilla x{num}."); } return ClampToHeadroom(num, headroom); } int num2 = _config.LinearPickupMultiplier.Value; if (num2 <= 0) { if (!_loggedLinearSanitize) { _log.LogWarning((object)"LinearPickupMultiplier must be > 0 — forcing 1."); _loggedLinearSanitize = true; } num2 = 1; } int globalExponentBase = Math.Max(1, _config.ExponentialBase.Value); globalExponentBase = _registry.GetApplicableExponentialBase(itemDef, globalExponentBase); double y = itemCountEffective; double num3 = Math.Pow(globalExponentBase, y); if (double.IsNaN(num3) || double.IsInfinity(num3) || num3 > 2147483647.0) { num3 = 2147483647.0; } double num4 = (double)num * (double)num2 * num3; if (double.IsNaN(num4) || double.IsInfinity(num4) || num4 > 2147483647.0) { num4 = 2147483647.0; } int val = (int)Math.Round(num4); val = Math.Max(num, val); val = ClampToHeadroom(val, headroom); if (_config.VerboseLogging.Value) { _log.LogDebug((object)$"Exponential grant for {((Object)itemDef).name}: stacks={itemCountEffective}, base={globalExponentBase}, linear={num2}, rawVanilla={num}, final={val}, cap={applicableMaxStacks}."); } return val; } private static int ClampToHeadroom(int amount, int headroom) { if (headroom <= 0) { return 0; } return Math.Min(Math.Max(amount, 0), headroom); } } public sealed class ItemConfigRegistry { private readonly ManualLogSource _log; private readonly ModConfig _config; private readonly HashSet<ItemDef> _filterEntries = new HashSet<ItemDef>(); private readonly Dictionary<ItemDef, int> _stackCaps = new Dictionary<ItemDef, int>(); private readonly Dictionary<ItemDef, int> _exponentialBases = new Dictionary<ItemDef, int>(); private bool _catalogRebuildQueued = true; public ItemConfigRegistry(ModConfig config, ManualLogSource log) { _config = config ?? throw new ArgumentNullException("config"); _log = log ?? throw new ArgumentNullException("log"); } public void RebuildCatalogCaches() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (ItemCatalog.allItemDefs.Length == 0) { _log.LogWarning((object)"ItemCatalog.allItemDefs empty — catalogs not initialized yet?"); return; } _filterEntries.Clear(); _stackCaps.Clear(); _exponentialBases.Clear(); foreach (string item in KeyValueListParser.ParseDelimitedList(_config.FilterItemIdentifiers.Value, _log, "FilterItemIdentifiers")) { if (TryResolveItemDef(item, out var def, "FilterItemIdentifiers") && _filterEntries.Add(def) && _config.VerboseLogging.Value) { _log.LogDebug((object)("Registered filter entry (" + DescribeMode() + "): \"" + item + "\" -> " + ((def != null) ? ((Object)def).name : null))); } } foreach (KeyValuePair<string, string> item2 in KeyValueListParser.ParseKeyValueMap(_config.ItemStackOverrideSpec.Value, _log, "ItemStackOverrideSpec")) { if (TryResolveItemDef(item2.Key, out var def2, "ItemStackOverrideSpec") && TryReadPositiveInt(item2.Key, item2.Value, out var value, "ItemStackOverrideSpec")) { _stackCaps[def2] = value; if (_config.VerboseLogging.Value) { _log.LogInfo((object)$"Applied stack override \"{((Object)def2).name}\" -> max {value}"); } } } foreach (KeyValuePair<string, string> item3 in KeyValueListParser.ParseKeyValueMap(_config.ItemExponentialBaseSpec.Value, _log, "ItemExponentialBaseSpec")) { if (!TryResolveItemDef(item3.Key, out var def3, "ItemExponentialBaseSpec") || !TryReadPositiveInt(item3.Key, item3.Value, out var value2, "ItemExponentialBaseSpec")) { continue; } if (value2 < 2) { _log.LogWarning((object)string.Format("[{0}] Exponential base must be >= 2 for \"{1}\" (got {2}); skipped.", "ItemExponentialBaseSpec", item3.Key, value2)); continue; } _exponentialBases[def3] = value2; if (_config.VerboseLogging.Value) { _log.LogInfo((object)$"Applied custom exponential base for \"{((Object)def3).name}\" -> {value2}"); } } _catalogRebuildQueued = false; _log.LogInfo((object)$"ExponentialItemsReloaded config cache rebuilt: filter entries={_filterEntries.Count}, stack overrides={_stackCaps.Count}, exp bases={_exponentialBases.Count}."); } public void RequestCatalogRebuild() { _catalogRebuildQueued = true; } public void RebuildCatalogCachesIfNeeded() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (_catalogRebuildQueued && ItemCatalog.allItemDefs.Length != 0) { RebuildCatalogCaches(); } } private string DescribeMode() { if (!_config.FilterIsWhitelistMode.Value) { return "blacklist"; } return "whitelist"; } public bool ShouldReceiveExponential(ItemDef itemDef) { if (!Object.op_Implicit((Object)(object)itemDef)) { return false; } bool flag = _filterEntries.Contains(itemDef); bool flag2 = (_config.FilterIsWhitelistMode.Value ? flag : (!flag)); if (!flag2 && _config.VerboseLogging.Value) { _log.LogDebug((object)("Filter (" + DescribeMode() + ") withheld exponentials from item \"" + ((Object)itemDef).name + "\".")); } return flag2; } public bool TryGetStackOverride(ItemDef itemDef, out int cap) { return _stackCaps.TryGetValue(itemDef, out cap); } public bool TryGetItemOverride(ItemDef itemDef, out int maxStacksCap) { return TryGetStackOverride(itemDef, out maxStacksCap); } public int GetApplicableMaxStacks(ItemDef itemDef, int globalCap) { int result = SanitizeGlobalCap(globalCap); if (!_stackCaps.TryGetValue(itemDef, out var value)) { return result; } return Math.Max(1, value); } public int GetApplicableExponentialBase(ItemDef itemDef, int globalExponentBase) { if (!_exponentialBases.TryGetValue(itemDef, out var value)) { return globalExponentBase; } return value; } private static int SanitizeGlobalCap(int globalCap) { if (globalCap <= 0) { return 1; } return Math.Min(globalCap, 2147479551); } public unsafe bool TryResolveItemDef(string key, out ItemDef def, string sourceOption) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) def = null; if (string.IsNullOrWhiteSpace(key)) { return false; } string text = key.Trim(); for (int i = 0; i < ItemCatalog.allItemDefs.Length; i++) { ItemDef val = (ItemDef)Unsafe.Read<object>((void*)ItemCatalog.allItemDefs[i]); if (Object.op_Implicit((Object)(object)val)) { if (string.Equals(((Object)val).name, text, StringComparison.OrdinalIgnoreCase)) { def = val; return true; } if (!string.IsNullOrEmpty(val.nameToken) && string.Equals(val.nameToken, text, StringComparison.OrdinalIgnoreCase)) { def = val; return true; } string text2 = NormalizeNameToken(val.nameToken); if (!string.IsNullOrEmpty(text2) && string.Equals(text2, text, StringComparison.OrdinalIgnoreCase)) { def = val; return true; } } } _log.LogWarning((object)("[" + sourceOption + "] Unknown item identifier \"" + text + "\". It may be typo'd, unloaded mod content, or locked behind DLC you do not own.")); return false; } private static string NormalizeNameToken(string token) { if (string.IsNullOrEmpty(token)) { return null; } if (token.StartsWith("ITEM_", StringComparison.OrdinalIgnoreCase) && token.EndsWith("_NAME", StringComparison.OrdinalIgnoreCase)) { int num = token.Length - 10; if (num > 0) { return token.Substring(5, num); } } return token; } private bool TryReadPositiveInt(string contextKey, string rawNumber, out int value, string sourceOption) { value = 0; if (!int.TryParse(rawNumber.Trim(), out var result)) { _log.LogWarning((object)("[" + sourceOption + "] \"" + contextKey + "\" has non-integer value \"" + rawNumber + "\".")); return false; } if (result <= 0) { _log.LogWarning((object)$"[{sourceOption}] \"{contextKey}\" must be positive (got {result}); skipped."); return false; } value = result; return true; } } } namespace ExponentialItemsReloaded.Hooks { [HarmonyPatch(typeof(Inventory), "GiveItem", new Type[] { typeof(ItemDef), typeof(int) })] internal static class InventoryGiveWithItemDefPatch { [HarmonyPrefix] internal static void Prefix(Inventory __instance, ItemDef itemDef, ref int count) { ExponentialItemsReloadedPlugin instance = ExponentialItemsReloadedPlugin.Instance; if (instance?.GrantEvaluator != null) { count = instance.GrantEvaluator.EvaluateAdjustedCount(__instance, itemDef, count); } } } } namespace ExponentialItemsReloaded.Content { public static class ExponentArtifact { public static ArtifactDef Definition { get; private set; } internal static void Register(ManualLogSource log) { try { Definition = ScriptableObject.CreateInstance<ArtifactDef>(); Definition.cachedName = "ArtifactOfExponents"; Definition.nameToken = "EXPONENTITEMSRELOADED_ARTIFACT_NAME"; Definition.descriptionToken = "EXPONENTITEMSRELOADED_ARTIFACT_DESC"; ArtifactDef command = Artifacts.Command; if (!Object.op_Implicit((Object)(object)command) || !Object.op_Implicit((Object)(object)command.smallIconSelectedSprite) || !Object.op_Implicit((Object)(object)command.smallIconDeselectedSprite)) { log.LogWarning((object)"ExponentArtifact could not inherit icons from ArtifactOfCommand — registration aborted."); Definition = null; return; } Definition.smallIconSelectedSprite = command.smallIconSelectedSprite; Definition.smallIconDeselectedSprite = command.smallIconDeselectedSprite; if (!ContentAddition.AddArtifactDef(Definition)) { log.LogWarning((object)"ContentAddition rejected ArtifactDef (catalog already initialized?). Exponential boosts may require RequireArtifact=false."); } LanguageAPI.Add(Definition.nameToken, "Artifact of Exponents"); LanguageAPI.Add(Definition.descriptionToken, "Item pickups grant exponentially increasing stacks."); } catch (Exception arg) { log.LogError((object)$"ExponentArtifact bootstrap failed — artifact gating unavailable: {arg}"); Definition = null; } } public static bool IsEnabledForCurrentRun() { if (!Object.op_Implicit((Object)(object)Definition)) { return false; } if (Object.op_Implicit((Object)(object)RunArtifactManager.instance)) { return RunArtifactManager.instance.IsArtifactEnabled(Definition); } return false; } } } namespace ExponentialItemsReloaded.Configuration { public static class ConfigParser { public static List<string> ParseFilterListEntries(string raw, ManualLogSource log, string diagnosticsName = "Blacklist / Whitelist identifiers") { return KeyValueListParser.ParseDelimitedList(raw, log, diagnosticsName); } public static Dictionary<string, string> ParseStackOverrides(string raw, ManualLogSource log) { return KeyValueListParser.ParseKeyValueMap(raw, log, "ItemStackOverrides"); } public static Dictionary<string, string> ParseExponentialBaseOverrides(string raw, ManualLogSource log) { return KeyValueListParser.ParseKeyValueMap(raw, log, "ItemExponentialBases"); } public static List<string> ParseBlacklist(string raw, ManualLogSource log) { return ParseFilterListEntries(raw, log, "Blacklist identifiers"); } } public static class KeyValueListParser { private static readonly char[] ListSeparators = new char[4] { ';', ',', '\n', '\r' }; public static List<string> ParseDelimitedList(string raw, ManualLogSource log, string optionName) { List<string> list = new List<string>(); if (string.IsNullOrWhiteSpace(raw)) { return list; } string[] array = raw.Split(ListSeparators, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0) { list.Add(text); } } return list; } public static Dictionary<string, string> ParseKeyValueMap(string raw, ManualLogSource log, string optionName) { Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrWhiteSpace(raw)) { return dictionary; } string[] array = raw.Split(ListSeparators, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length == 0) { continue; } int num = text.IndexOf('='); if (num <= 0 || num >= text.Length - 1) { if (log != null) { log.LogWarning((object)("[" + optionName + "] Ignoring invalid entry (expected Key=Value): \"" + text + "\"")); } continue; } string text2 = text.Substring(0, num).Trim(); string value = text.Substring(num + 1).Trim(); if (text2.Length == 0) { if (log != null) { log.LogWarning((object)("[" + optionName + "] Ignoring entry with empty key: \"" + text + "\"")); } } else { dictionary[text2] = value; } } return dictionary; } } public sealed class ModConfig { public ConfigEntry<bool> Enabled { get; } public ConfigEntry<bool> RequireArtifact { get; } public ConfigEntry<int> LinearPickupMultiplier { get; } public ConfigEntry<int> ExponentialBase { get; } public ConfigEntry<int> GlobalMaxItemStacks { get; } public ConfigEntry<bool> FilterIsWhitelistMode { get; } public ConfigEntry<string> FilterItemIdentifiers { get; } public ConfigEntry<string> ItemStackOverrideSpec { get; } public ConfigEntry<string> ItemExponentialBaseSpec { get; } public ConfigEntry<bool> VerboseLogging { get; } public ConfigFile Bindings { get; } internal ModConfig(ConfigFile configFile) { Bindings = configFile ?? throw new ArgumentNullException("configFile"); Enabled = Bindings.Bind<bool>("0_Global", "Enabled", true, "Master enable for exponential pickups. When false, the plugin restores vanilla grant counts."); RequireArtifact = Bindings.Bind<bool>("0_Global", "RequireArtifact", true, "If true, exponential math only applies when Artifact of Exponents is enabled on the server for the current run."); LinearPickupMultiplier = Bindings.Bind<int>("0_Global", "LinearPickupMultiplier", 1, "Multiply the incoming vanilla pickup quantity by this linear factor before exponentials."); ExponentialBase = Bindings.Bind<int>("0_Global", "ExponentialBase", 2, "Integer base raised to power of existing stacks when computing bonus pickup size (2 mimics legacy 1-2-4-8 pacing)."); GlobalMaxItemStacks = Bindings.Bind<int>("0_Global", "GlobalMaxItemStacks", 4096, "Hard cap applied to inventories for exponential grants when no override is defined (also bounds math to avoid overflows)."); FilterIsWhitelistMode = Bindings.Bind<bool>("1_Filter", "FilterIsWhitelistMode", false, "If false: identifiers listed in FilterItemIdentifiers are blacklisted (no exponentials).\nIf true: only those identifiers receive exponentials (whitelist mode)."); FilterItemIdentifiers = Bindings.Bind<string>("1_Filter", "FilterItemIdentifiers", string.Empty, "Semicolon-, comma-, or newline-separated identifiers (ItemDef.name or catalog names). Examples: BoostSyringe; PaulsGoatHoof; Feather"); ItemStackOverrideSpec = Bindings.Bind<string>("2_ItemStackOverrides", "ItemStackOverrideSpec", string.Empty, "Per-item stack caps overriding GlobalMaxItemStacks.\nSyntax: BoostSyringe=1024; PaulsGoatHoof=32; LensMakersGlasses=64\nInvalid rows are skipped with warnings."); ItemExponentialBaseSpec = Bindings.Bind<string>("2_ItemStackOverrides", "ItemExponentialBaseSpec", string.Empty, "Optional per-item exponential bases (fallback to Global ExponentialBase if missing).\nSyntax: BoostSyringe=3; PaulsGoatHoof=2"); VerboseLogging = Bindings.Bind<bool>("9_Debug", "VerboseLogging", false, "Extra BepInEx logging for blacklist/whitelist hits, lookups, overrides, and grant computations."); } } }