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 CosmeticBoxConfig v1.0.0
CosmeticBoxConfig.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("CosmeticBoxConfig")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("CosmeticBoxConfig")] [assembly: AssemblyTitle("CosmeticBoxConfig")] [assembly: AssemblyVersion("1.0.0.0")] [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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 CosmeticBoxConfig { internal static class PluginInfo { public const string GUID = "cosmetic.box.config"; public const string NAME = "CosmeticBoxConfig"; public const string VERSION = "1.0.0"; } internal enum SpawnMode { Random, Fixed } internal readonly struct LevelSettings { public SpawnMode Mode { get; } public int BoxCount { get; } public int LoopMax { get; } public int CompensationLoopMax { get; } public LevelSettings(SpawnMode mode, int boxCount) { Mode = mode; BoxCount = Mathf.Clamp(boxCount, 0, 20); LoopMax = ((mode == SpawnMode.Fixed) ? GetTimeFormulaLoopMax(BoxCount) : 0); CompensationLoopMax = ((mode == SpawnMode.Fixed) ? GetCompensationLoopMax(BoxCount) : 0); } private static int GetTimeFormulaLoopMax(int boxCount) { if (boxCount > 0) { return boxCount - 1; } return -1; } private static int GetCompensationLoopMax(int boxCount) { if (boxCount > 0) { return Mathf.Max(boxCount - 1, boxCount * 3 - 1); } return -1; } } [BepInPlugin("cosmetic.box.config", "CosmeticBoxConfig", "1.0.0")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Log = null; private static ConfigEntry<SpawnMode> _mode = null; private static ConfigEntry<int> _boxCount = null; private static readonly object SettingsLock = new object(); private static LevelSettings _pendingSettings = new LevelSettings(SpawnMode.Random, 1); private static LevelSettings _activeSettings = new LevelSettings(SpawnMode.Random, 1); private static int _actualBoxesThisLevel; private static bool _patchesEnabled; internal static LevelSettings ActiveSettings { get { lock (SettingsLock) { return _activeSettings; } } } internal static int ActualBoxesThisLevel { get { lock (SettingsLock) { return _actualBoxesThisLevel; } } } private void Awake() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; _mode = ((BaseUnityPlugin)this).Config.Bind<SpawnMode>("General", "Mode", SpawnMode.Random, new ConfigDescription("Spawn mode:\n Random - At least 1 actual cosmetic box when an original spawn volume is available; remaining rolls use vanilla probability.\n Fixed - Targets BoxCount actual cosmetic boxes when original spawn volumes are available, with compensation attempts.\nChanges apply on the next level load, not mid-level.", (AcceptableValueBase)null, Array.Empty<object>())); _boxCount = ((BaseUnityPlugin)this).Config.Bind<int>("General", "BoxCount", 1, new ConfigDescription("Fixed mode cosmetic boxes.\n 0 = 0 cosmetic boxes.\n 1-20 = target actual cosmetic box count, limited by original spawn-volume availability.\nIgnored in Random mode. Changes apply on the next level load.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20), Array.Empty<object>())); UpdatePendingSettings(); ActivatePendingSettings(); ((BaseUnityPlugin)this).Config.SettingChanged += delegate { UpdatePendingSettings(); }; _patchesEnabled = TryPatchAll(new Harmony("cosmetic.box.config")); Log.LogInfo((object)("CosmeticBoxConfig v1.0.0 loaded - patches " + (_patchesEnabled ? "enabled" : "disabled") + "; chance gate " + (PatchMethods.ChanceGatePatchActive ? "active" : "inactive") + "; active " + Describe(ActiveSettings))); } private static bool TryPatchAll(Harmony harmony) { //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Expected O, but got Unknown //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Expected O, but got Unknown //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Expected O, but got Unknown //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Expected O, but got Unknown //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Expected O, but got Unknown //IL_0251: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(typeof(ValuableDirector), "SetupHost", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(ValuableDirector), "CosmeticWorldObjectLevelLoopsGet", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(ValuableDirector), "CosmeticWorldObjectLevelLoopsClampedGet", (Type[])null, (Type[])null); MethodInfo methodInfo4 = AccessTools.Method(typeof(ValuableDirector), "SpawnCosmeticWorldObject", (Type[])null, (Type[])null); MethodInfo iteratorMoveNext = GetIteratorMoveNext(methodInfo); FieldInfo fieldInfo = AccessTools.Field(typeof(ValuableDirector), "cosmeticWorldObjectTargetAmount"); if (methodInfo == null || iteratorMoveNext == null || methodInfo2 == null || methodInfo3 == null || methodInfo4 == null || fieldInfo == null) { Log.LogError((object)("Required game methods were not found; CosmeticBoxConfig will not patch anything. SetupHost=" + ((methodInfo != null) ? "ok" : "missing") + ", SetupHost.MoveNext=" + ((iteratorMoveNext != null) ? "ok" : "missing") + ", CosmeticWorldObjectLevelLoopsGet=" + ((methodInfo2 != null) ? "ok" : "missing") + ", CosmeticWorldObjectLevelLoopsClampedGet=" + ((methodInfo3 != null) ? "ok" : "missing") + ", SpawnCosmeticWorldObject=" + ((methodInfo4 != null) ? "ok" : "missing") + ", cosmeticWorldObjectTargetAmount=" + ((fieldInfo != null) ? "ok" : "missing"))); return false; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(PatchMethods), "SetupHostPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(PatchMethods), "LoopsGetPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(PatchMethods), "LoopsClampedGetPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)iteratorMoveNext, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(PatchMethods), "SetupHostMoveNextTranspiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo4, new HarmonyMethod(typeof(PatchMethods), "SpawnCosmeticWorldObjectPrefix", (Type[])null), new HarmonyMethod(typeof(PatchMethods), "SpawnCosmeticWorldObjectPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return true; } catch (Exception arg) { Log.LogError((object)$"Failed to register CosmeticBoxConfig patches; attempting to roll back any partial patches. {arg}"); try { harmony.UnpatchSelf(); Log.LogInfo((object)"Rolled back CosmeticBoxConfig patches after registration failure."); } catch (Exception arg2) { Log.LogError((object)$"Failed to roll back partial CosmeticBoxConfig patches. {arg2}"); } return false; } } private static MethodInfo? GetIteratorMoveNext(MethodInfo? method) { Type type = method?.GetCustomAttribute<IteratorStateMachineAttribute>()?.StateMachineType; if (!(type == null)) { return AccessTools.Method(type, "MoveNext", (Type[])null, (Type[])null); } return null; } internal static void ActivatePendingSettingsForLevel() { lock (SettingsLock) { _activeSettings = _pendingSettings; _actualBoxesThisLevel = 0; } Log.LogInfo((object)("CosmeticBoxConfig level settings active: " + Describe(ActiveSettings))); } internal static void ActivatePendingSettings() { lock (SettingsLock) { _activeSettings = _pendingSettings; } Log.LogInfo((object)("CosmeticBoxConfig settings active: " + Describe(ActiveSettings))); } internal static void RecordActualBoxSpawned() { lock (SettingsLock) { _actualBoxesThisLevel++; } } internal static bool NeedsGuaranteedBox() { TryGetGuaranteeState(out var settings, out var actual); if (settings.Mode != SpawnMode.Fixed) { return actual < 1; } return actual < settings.BoxCount; } internal static bool TryGetGuaranteeState(out LevelSettings settings, out int actual) { lock (SettingsLock) { settings = _activeSettings; actual = _actualBoxesThisLevel; } if (settings.Mode != SpawnMode.Fixed) { return true; } return settings.BoxCount > 0; } private static void UpdatePendingSettings() { LevelSettings levelSettings = ReadSettingsFromConfig(); lock (SettingsLock) { _pendingSettings = levelSettings; } Log.LogInfo((object)("CosmeticBoxConfig config queued for next level: " + Describe(levelSettings))); } private static LevelSettings ReadSettingsFromConfig() { return new LevelSettings(_mode.Value, _boxCount.Value); } private static string Describe(LevelSettings settings) { if (settings.Mode != SpawnMode.Fixed) { return "Random, minimum actual boxes=1 then vanilla probability"; } return $"Fixed, target boxes={settings.BoxCount}, loopMax={settings.LoopMax}, compensationLoopMax={settings.CompensationLoopMax}"; } } internal static class PatchMethods { private const int ForcedFailureRoll = 99999; private static readonly FieldInfo TargetAmountField = AccessTools.Field(typeof(ValuableDirector), "cosmeticWorldObjectTargetAmount"); private static bool _chanceGatePatchActive; internal static bool ChanceGatePatchActive => _chanceGatePatchActive; internal static void SetupHostPrefix() { Plugin.ActivatePendingSettingsForLevel(); } internal static IEnumerable<CodeInstruction> SetupHostMoveNextTranspiler(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = instructions.ToList(); MethodInfo methodInfo = AccessTools.Method(typeof(Random), "Range", new Type[2] { typeof(int), typeof(int) }, (Type[])null); MethodInfo operand = AccessTools.Method(typeof(PatchMethods), "GuaranteedChanceRoll", (Type[])null, (Type[])null); List<int> list2 = new List<int>(); for (int i = 0; i <= list.Count - 3; i++) { if (IsLdcI4(list[i], 0) && IsLdcI4(list[i + 1], 100) && CodeInstructionExtensions.Calls(list[i + 2], methodInfo)) { list2.Add(i); } } if (list2.Count != 1) { _chanceGatePatchActive = false; string text = $"Expected exactly one cosmetic Random.Range(0,100) chance gate in SetupHost.MoveNext, found {list2.Count}; rolling back patches."; Plugin.Log.LogError((object)text); throw new InvalidOperationException(text); } list[list2[0] + 2].operand = operand; _chanceGatePatchActive = true; Plugin.Log.LogInfo((object)"Patched SetupHost.MoveNext cosmetic chance gate."); return list; } internal static int GuaranteedChanceRoll(int min, int max) { int result = Random.Range(min, max); Plugin.TryGetGuaranteeState(out var settings, out var actual); if (settings.Mode == SpawnMode.Fixed) { if (actual >= settings.BoxCount) { return 99999; } return min; } if (actual >= 1) { return result; } return min; } internal static void LoopsGetPostfix(ref int __result) { LevelSettings activeSettings = Plugin.ActiveSettings; if (activeSettings.Mode == SpawnMode.Fixed) { __result = activeSettings.LoopMax; } } internal static void LoopsClampedGetPostfix(ref int __result) { LevelSettings activeSettings = Plugin.ActiveSettings; __result = ((activeSettings.Mode == SpawnMode.Fixed) ? activeSettings.CompensationLoopMax : Mathf.Max(__result, 0)); } internal static void SpawnCosmeticWorldObjectPrefix(ValuableDirector __instance, ref Rarity _cosmeticRarity, int[] _volumeIndex, List<ValuableVolume>[] _volumes, out int __state) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected I4, but got Unknown __state = GetTargetAmount(__instance); try { if (Plugin.NeedsGuaranteedBox() && !HasAvailableVolume(__instance, _cosmeticRarity, _volumeIndex, _volumes) && TryFindAvailableRarity(__instance, _volumeIndex, _volumes, out var rarity)) { _cosmeticRarity = (Rarity)(int)rarity; } } catch (Exception arg) { Plugin.Log.LogError((object)$"SpawnCosmeticWorldObjectPrefix failed; leaving vanilla spawn logic unchanged. {arg}"); } } internal static void SpawnCosmeticWorldObjectPostfix(ValuableDirector __instance, int __state) { try { if (GetTargetAmount(__instance) > __state) { Plugin.RecordActualBoxSpawned(); } } catch (Exception arg) { Plugin.Log.LogError((object)$"SpawnCosmeticWorldObjectPostfix failed. {arg}"); } } private static int GetTargetAmount(ValuableDirector director) { if ((Object)(object)director == (Object)null || TargetAmountField == null || TargetAmountField.FieldType != typeof(int)) { return 0; } try { return (int)TargetAmountField.GetValue(director); } catch (Exception arg) { Plugin.Log.LogError((object)$"Failed to read cosmeticWorldObjectTargetAmount. {arg}"); return 0; } } private static bool TryFindAvailableRarity(ValuableDirector director, int[] volumeIndex, List<ValuableVolume>[] volumes, out Rarity rarity) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected I4, but got Unknown if (director?.cosmeticWorldObjectSetups == null) { rarity = (Rarity)0; return false; } for (int i = 0; i < director.cosmeticWorldObjectSetups.Count; i++) { if (Enum.IsDefined(typeof(Rarity), i) && director.cosmeticWorldObjectSetups[i] != null) { Rarity val = (Rarity)i; if (HasAvailableVolume(director, val, volumeIndex, volumes)) { rarity = (Rarity)(int)val; return true; } } } rarity = (Rarity)0; return false; } private static bool TryGetVolumeIndexForRarity(ValuableDirector director, Rarity rarity, out int volumeIndex) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) volumeIndex = 0; if (director?.cosmeticWorldObjectSetups == null) { return false; } int num = Convert.ToInt32(rarity); if (num < 0 || num >= director.cosmeticWorldObjectSetups.Count) { return false; } CosmeticWorldObjectSetup val = director.cosmeticWorldObjectSetups[num]; if (val == null) { return false; } volumeIndex = Convert.ToInt32(val.volume); return true; } private static bool HasAvailableVolume(ValuableDirector director, Rarity rarity, int[] volumeIndex, List<ValuableVolume>[] volumes) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if (TryGetVolumeIndexForRarity(director, rarity, out var volumeIndex2) && volumes != null && volumeIndex != null && volumeIndex2 >= 0 && volumeIndex2 < volumes.Length && volumeIndex2 < volumeIndex.Length && volumes[volumeIndex2] != null && volumeIndex[volumeIndex2] >= 0) { return volumeIndex[volumeIndex2] < volumes[volumeIndex2].Count; } return false; } private static bool IsLdcI4(CodeInstruction instruction, int expected) { if (instruction.opcode == OpCodes.Ldc_I4_M1) { return expected == -1; } if (instruction.opcode == OpCodes.Ldc_I4_0) { return expected == 0; } if (instruction.opcode == OpCodes.Ldc_I4_1) { return expected == 1; } if (instruction.opcode == OpCodes.Ldc_I4_2) { return expected == 2; } if (instruction.opcode == OpCodes.Ldc_I4_3) { return expected == 3; } if (instruction.opcode == OpCodes.Ldc_I4_4) { return expected == 4; } if (instruction.opcode == OpCodes.Ldc_I4_5) { return expected == 5; } if (instruction.opcode == OpCodes.Ldc_I4_6) { return expected == 6; } if (instruction.opcode == OpCodes.Ldc_I4_7) { return expected == 7; } if (instruction.opcode == OpCodes.Ldc_I4_8) { return expected == 8; } if (instruction.opcode == OpCodes.Ldc_I4_S || instruction.opcode == OpCodes.Ldc_I4) { return Convert.ToInt32(instruction.operand) == expected; } return false; } } }