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 InteriorScrapTweaks v1.0.0
InteriorScrapTweaks.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using DunGen; using DunGen.Graph; using HarmonyLib; using LethalLevelLoader; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; [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("InteriorScrapTweaks")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("InteriorScrapTweaks")] [assembly: AssemblyTitle("InteriorScrapTweaks")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 InteriorScrapTweaks { internal static class InteriorResolver { private static bool _lethalLevelLoaderResolutionFailed; internal static List<string> GetInteriorNameCandidates(RoundManager roundManager) { List<string> list = new List<string>(); try { string text = TryGetLethalLevelLoaderDungeonName(); if (!string.IsNullOrEmpty(text)) { list.Add(text); } } catch (Exception arg) { ManualLogSource modLogger = Plugin.ModLogger; if (modLogger != null) { modLogger.LogWarning((object)$"[InteriorScrapTweaks] Failed to resolve LLL dungeon name, skipping it: {arg}"); } } try { RuntimeDungeon dungeonGenerator = roundManager.dungeonGenerator; object obj; if (dungeonGenerator == null) { obj = null; } else { DungeonGenerator generator = dungeonGenerator.Generator; if (generator == null) { obj = null; } else { DungeonFlow dungeonFlow = generator.DungeonFlow; obj = ((dungeonFlow != null) ? ((Object)dungeonFlow).name : null); } } string text2 = (string)obj; if (!string.IsNullOrEmpty(text2) && !ContainsInteriorName(list, text2)) { list.Add(text2); } } catch (Exception arg2) { ManualLogSource modLogger2 = Plugin.ModLogger; if (modLogger2 != null) { modLogger2.LogWarning((object)$"[InteriorScrapTweaks] Failed to read DungeonFlow name from dungeonGenerator, skipping it: {arg2}"); } } try { if (roundManager.dungeonFlowTypes != null && roundManager.currentDungeonType >= 0 && roundManager.currentDungeonType < roundManager.dungeonFlowTypes.Length) { IndoorMapType obj2 = roundManager.dungeonFlowTypes[roundManager.currentDungeonType]; object obj3; if (obj2 == null) { obj3 = null; } else { DungeonFlow dungeonFlow2 = obj2.dungeonFlow; obj3 = ((dungeonFlow2 != null) ? ((Object)dungeonFlow2).name : null); } string text3 = (string)obj3; if (!string.IsNullOrEmpty(text3) && !ContainsInteriorName(list, text3)) { list.Add(text3); } } } catch (Exception arg3) { ManualLogSource modLogger3 = Plugin.ModLogger; if (modLogger3 != null) { modLogger3.LogWarning((object)$"[InteriorScrapTweaks] Failed to read DungeonFlow name from dungeonFlowTypes[{roundManager?.currentDungeonType}], skipping it: {arg3}"); } } try { list.Add("Type_" + roundManager?.currentDungeonType); } catch (Exception arg4) { ManualLogSource modLogger4 = Plugin.ModLogger; if (modLogger4 != null) { modLogger4.LogWarning((object)$"[InteriorScrapTweaks] Failed to add numeric interior fallback key: {arg4}"); } } return list; } private static bool ContainsInteriorName(List<string> candidates, string candidateName) { foreach (string candidate in candidates) { if (string.Equals(candidate, candidateName, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private static string TryGetLethalLevelLoaderDungeonName() { if (_lethalLevelLoaderResolutionFailed) { return null; } try { return LethalLevelLoaderIntegration.GetCurrentDungeonName(); } catch (FileNotFoundException ex) { _lethalLevelLoaderResolutionFailed = true; ManualLogSource modLogger = Plugin.ModLogger; if (modLogger != null) { modLogger.LogInfo((object)("[InteriorScrapTweaks] LethalLevelLoader not found, matching interiors by DungeonFlow name only. (" + ex.Message + ")")); } return null; } catch (FileLoadException ex2) { _lethalLevelLoaderResolutionFailed = true; ManualLogSource modLogger2 = Plugin.ModLogger; if (modLogger2 != null) { modLogger2.LogInfo((object)("[InteriorScrapTweaks] LethalLevelLoader could not be loaded, matching interiors by DungeonFlow name only. (" + ex2.Message + ")")); } return null; } catch (Exception arg) { _lethalLevelLoaderResolutionFailed = true; ManualLogSource modLogger3 = Plugin.ModLogger; if (modLogger3 != null) { modLogger3.LogWarning((object)$"[InteriorScrapTweaks] Failed to read LethalLevelLoader CurrentExtendedDungeonFlow.DungeonName, LLL matching disabled for this session: {arg}"); } return null; } } } internal static class LethalLevelLoaderIntegration { internal static string GetCurrentDungeonName() { ExtendedDungeonFlow currentExtendedDungeonFlow = DungeonManager.CurrentExtendedDungeonFlow; if (currentExtendedDungeonFlow == null) { return null; } return currentExtendedDungeonFlow.DungeonName; } } [BepInPlugin("CunningFox146.InteriorScrapTweaks", "InteriorScrapTweaks", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "CunningFox146.InteriorScrapTweaks"; public const string PluginName = "InteriorScrapTweaks"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource ModLogger; internal static ConfigEntry<float> DefaultScrapCountMultiplier; internal static ConfigEntry<float> DefaultScrapValueMultiplier; internal static ConfigEntry<string> ScrapCountMultipliers; internal static ConfigEntry<string> ScrapValueMultipliers; internal static ConfigEntry<bool> LogDetectedInteriorNames; private void Awake() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_00f2: Unknown result type (might be due to invalid IL or missing references) ModLogger = ((BaseUnityPlugin)this).Logger; DefaultScrapCountMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "DefaultScrapCountMultiplier", 1f, new ConfigDescription("Scrap-count multiplier used for interiors not listed in ScrapCountMultipliers.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); DefaultScrapValueMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "DefaultScrapValueMultiplier", 1f, new ConfigDescription("Scrap-value multiplier used for interiors not listed in ScrapValueMultipliers.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); ScrapCountMultipliers = ((BaseUnityPlugin)this).Config.Bind<string>("Interiors", "ScrapCountMultipliers", "Factory=1.0, Mansion=1.5, Mineshaft=0.7, Sewer=1.0, Level1Flow=1.0, Level2Flow=1.5, Level3Flow=0.7", "Per-interior scrap-COUNT multipliers. Format: \"Name=Multiplier, Name2=Multiplier2\" (separators: comma/semicolon/newline between entries, '=' or ':' between key and value). Keys match the LethalLevelLoader dungeon name when LLL is installed, otherwise the DungeonFlow asset name. Check the BepInEx console/log for the exact \"Interior keys\" line logged on level generation."); ScrapValueMultipliers = ((BaseUnityPlugin)this).Config.Bind<string>("Interiors", "ScrapValueMultipliers", "Factory=1.0, Mansion=1.0, Mineshaft=1.0, Sewer=1.0, Level1Flow=1.0, Level2Flow=1.0, Level3Flow=1.0", "Per-interior scrap-VALUE multipliers (average value per item). Same format and key matching as ScrapCountMultipliers."); LogDetectedInteriorNames = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "LogDetectedInteriorNames", true, "Log the detected interior keys and applied multipliers every time scrap spawns. Use the logged keys in ScrapCountMultipliers/ScrapValueMultipliers to target modded interiors. You can turn this off once your config is settled."); new Harmony("CunningFox146.InteriorScrapTweaks").PatchAll(typeof(ScrapSpawnPatches)); ModLogger.LogInfo((object)"InteriorScrapTweaks v1.0.0 loaded. Scrap amount/value will be scaled per interior."); } } internal static class ScrapMultiplierConfig { public static Dictionary<string, float> ParseMultiplierTable(string rawTableText, ManualLogSource logger, string tableName) { Dictionary<string, float> dictionary = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrWhiteSpace(rawTableText)) { return dictionary; } string[] array = rawTableText.Split(new char[4] { ',', ';', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text in array) { string[] array2 = text.Split(new char[2] { '=', ':' }, 2); if (array2.Length != 2) { if (logger != null) { logger.LogWarning((object)("[InteriorScrapTweaks] Ignoring malformed entry in " + tableName + ": \"" + text.Trim() + "\" (expected Key=Multiplier).")); } continue; } string text2 = array2[0].Trim(); string s = array2[1].Trim(); float result; if (text2.Length == 0) { if (logger != null) { logger.LogWarning((object)("[InteriorScrapTweaks] Ignoring entry with empty key in " + tableName + ": \"" + text.Trim() + "\".")); } } else if (float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out result)) { if (!float.IsFinite(result)) { if (logger != null) { logger.LogWarning((object)("[InteriorScrapTweaks] Ignoring non-finite multiplier in " + tableName + ": \"" + text.Trim() + "\".")); } continue; } if (result < 0f) { if (logger != null) { logger.LogWarning((object)("[InteriorScrapTweaks] Clamping negative multiplier to 0 in " + tableName + ": \"" + text.Trim() + "\".")); } result = 0f; } dictionary[text2] = result; } else if (logger != null) { logger.LogWarning((object)("[InteriorScrapTweaks] Ignoring entry with non-numeric multiplier in " + tableName + ": \"" + text.Trim() + "\".")); } } return dictionary; } public static float FindMultiplierForInterior(IReadOnlyList<string> interiorNameCandidates, Dictionary<string, float> multipliersByInteriorName, float defaultMultiplier) { if (interiorNameCandidates == null) { return defaultMultiplier; } foreach (string interiorNameCandidate in interiorNameCandidates) { if (interiorNameCandidate != null && multipliersByInteriorName.TryGetValue(interiorNameCandidate, out var value)) { return value; } } return defaultMultiplier; } } [HarmonyPatch(typeof(RoundManager), "SpawnScrapInLevel")] internal static class ScrapSpawnPatches { private static int _originalMinimumScrapCount; private static int _originalMaximumScrapCount; private static int _originalMinimumTotalScrapValue; private static int _originalMaximumTotalScrapValue; private static float _originalScrapValueMultiplier; private static bool _scrapValuesWereAdjusted; private const int MaximumSpawnedScrapCount = 1000; private const float MaximumScrapValueMultiplier = 100000f; private static void Prefix(RoundManager __instance) { _scrapValuesWereAdjusted = false; try { if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.currentLevel == (Object)null) { return; } bool flag; try { flag = ((NetworkBehaviour)__instance).IsServer; } catch (Exception arg) { ManualLogSource modLogger = Plugin.ModLogger; if (modLogger != null) { modLogger.LogWarning((object)$"[InteriorScrapTweaks] Failed to check IsServer, assuming host: {arg}"); } flag = true; } if (!flag) { return; } List<string> interiorNameCandidates = InteriorResolver.GetInteriorNameCandidates(__instance); Dictionary<string, float> multipliersByInteriorName = ScrapMultiplierConfig.ParseMultiplierTable(Plugin.ScrapCountMultipliers.Value, Plugin.ModLogger, "ScrapCountMultipliers"); Dictionary<string, float> multipliersByInteriorName2 = ScrapMultiplierConfig.ParseMultiplierTable(Plugin.ScrapValueMultipliers.Value, Plugin.ModLogger, "ScrapValueMultipliers"); float num = ScrapMultiplierConfig.FindMultiplierForInterior(interiorNameCandidates, multipliersByInteriorName, Plugin.DefaultScrapCountMultiplier.Value); float num2 = ScrapMultiplierConfig.FindMultiplierForInterior(interiorNameCandidates, multipliersByInteriorName2, Plugin.DefaultScrapValueMultiplier.Value); if (Plugin.LogDetectedInteriorNames.Value) { ManualLogSource modLogger2 = Plugin.ModLogger; if (modLogger2 != null) { modLogger2.LogInfo((object)("[InteriorScrapTweaks] Interior keys: " + string.Join(" | ", interiorNameCandidates) + " " + $"-> scrap amount x{num}, scrap value x{num2} " + $"(base min={__instance.currentLevel.minScrap} max={__instance.currentLevel.maxScrap} " + $"valueMult={__instance.scrapValueMultiplier}).")); } } if (Mathf.Approximately(num, 1f) && Mathf.Approximately(num2, 1f)) { return; } SelectableLevel currentLevel = __instance.currentLevel; _originalMinimumScrapCount = currentLevel.minScrap; _originalMaximumScrapCount = currentLevel.maxScrap; _originalMinimumTotalScrapValue = currentLevel.minTotalScrapValue; _originalMaximumTotalScrapValue = currentLevel.maxTotalScrapValue; _originalScrapValueMultiplier = __instance.scrapValueMultiplier; int num3 = Math.Min(1000, Math.Max(0, RoundToInteger((float)_originalMinimumScrapCount * num))); int num4 = Math.Min(1000, Math.Max(num3, RoundToInteger((float)_originalMaximumScrapCount * num))); if (num3 == 1000 || num4 == 1000) { ManualLogSource modLogger3 = Plugin.ModLogger; if (modLogger3 != null) { modLogger3.LogWarning((object)$"[InteriorScrapTweaks] Scrap count for this interior hit the safety cap of {1000} items; check your ScrapCountMultipliers for typos."); } } float num5 = Math.Min(100000f, _originalScrapValueMultiplier * num2); if (num5 < _originalScrapValueMultiplier * num2) { ManualLogSource modLogger4 = Plugin.ModLogger; if (modLogger4 != null) { modLogger4.LogWarning((object)$"[InteriorScrapTweaks] Scrap value multiplier for this interior hit the safety cap of x{100000f}; check your ScrapValueMultipliers for typos."); } } currentLevel.minScrap = num3; currentLevel.maxScrap = num4; currentLevel.minTotalScrapValue = Math.Max(0, RoundToInteger((float)_originalMinimumTotalScrapValue * num * num2)); currentLevel.maxTotalScrapValue = Math.Max(currentLevel.minTotalScrapValue, RoundToInteger((float)_originalMaximumTotalScrapValue * num * num2)); __instance.scrapValueMultiplier = num5; _scrapValuesWereAdjusted = true; } catch (Exception arg2) { ManualLogSource modLogger5 = Plugin.ModLogger; if (modLogger5 != null) { modLogger5.LogError((object)$"[InteriorScrapTweaks] Failed to apply interior scrap multipliers: {arg2}"); } } } private static void Postfix(RoundManager __instance) { if (!_scrapValuesWereAdjusted) { return; } try { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.currentLevel == (Object)null)) { SelectableLevel currentLevel = __instance.currentLevel; currentLevel.minScrap = _originalMinimumScrapCount; currentLevel.maxScrap = _originalMaximumScrapCount; currentLevel.minTotalScrapValue = _originalMinimumTotalScrapValue; currentLevel.maxTotalScrapValue = _originalMaximumTotalScrapValue; __instance.scrapValueMultiplier = _originalScrapValueMultiplier; } } catch (Exception arg) { ManualLogSource modLogger = Plugin.ModLogger; if (modLogger != null) { modLogger.LogError((object)$"[InteriorScrapTweaks] Failed to restore scrap values: {arg}"); } } finally { _scrapValuesWereAdjusted = false; } } private static int RoundToInteger(double valueToRound) { if (double.IsNaN(valueToRound) || valueToRound <= 0.0) { return 0; } if (valueToRound >= 2147483647.0) { return int.MaxValue; } return (int)Math.Round(valueToRound, MidpointRounding.AwayFromZero); } } }