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 ScavengerBeforeLoop v1.1.0
plugins/ScavengerBeforeLoop/ScavengerBeforeLoop.dll
Decompiled 2 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using LocalTweaks; using Microsoft.CodeAnalysis; using RiskOfOptions; using RiskOfOptions.OptionConfigs; using RiskOfOptions.Options; 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("ScavengerBeforeLoop")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0+d4d36d5759f75596df6a59e21ff454dadbe00631")] [assembly: AssemblyProduct("ScavengerBeforeLoop")] [assembly: AssemblyTitle("ScavengerBeforeLoop")] [assembly: AssemblyVersion("1.1.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 ScavengerBeforeLoop { [BepInPlugin("com.youssef.ScavengerBeforeLoop", "Scavenger Before Loop", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { private enum ItemMultiplier { Double = 2, Triple } public const string Guid = "com.youssef.ScavengerBeforeLoop"; public const string Name = "Scavenger Before Loop"; private static Plugin instance; private ConfigEntry<bool> onePerStage; private ConfigEntry<int> spawnInterval; private ConfigEntry<int> healthPercent; private ConfigEntry<ItemMultiplier> itemMultiplier; private readonly Harmony harmony = new Harmony("com.youssef.ScavengerBeforeLoop"); private SceneInfo trackedScene; private SceneInfo populatedScene; private CharacterSpawnCard scavenger; private Xoroshiro128Plus rng; private int spawned; private int failedAttempts; private bool spawning; private float nextSpawn; private float nextAttempt; private void Awake() { //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Expected O, but got Unknown //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Expected O, but got Unknown //IL_016c: Expected O, but got Unknown //IL_016c: Expected O, but got Unknown //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Expected O, but got Unknown //IL_01bb: Expected O, but got Unknown //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Expected O, but got Unknown instance = this; onePerStage = TweakSettings.Checkbox(((BaseUnityPlugin)this).Config, "Scavengers", "Maximum one per stage", value: true, "Limit stage 5 to one Scavenger in total, even after it dies. Uncheck for repeated spawns until the teleporter finishes. Existing enemies are never removed.", "com.youssef.ScavengerBeforeLoop", "Scavenger Before Loop"); spawnInterval = TweakSettings.Slider(((BaseUnityPlugin)this).Config, "Scavengers", "Repeat interval seconds", 90, 10, 600, "Time between Scavenger spawns when the one-per-stage limit is disabled. The first one still appears on stage entry.", "com.youssef.ScavengerBeforeLoop", "Scavenger Before Loop"); healthPercent = TweakSettings.Slider(((BaseUnityPlugin)this).Config, "Strength", "Health percent", 100, 50, 300, "Maximum health for Scavengers on stage 5. 100 is the original value.", "com.youssef.ScavengerBeforeLoop", "Scavenger Before Loop"); itemMultiplier = ((BaseUnityPlugin)this).Config.Bind<ItemMultiplier>("Strength", "Item stacks", ItemMultiplier.Double, "Give stage 5 Scavengers double or triple their normal common, uncommon and legendary item stacks. Equipment is unchanged."); ModSettingsManager.AddOption((BaseOption)new ChoiceOption((ConfigEntryBase)(object)itemMultiplier), "com.youssef.ScavengerBeforeLoop", "Scavenger Before Loop"); ModSettingsManager.SetModDescription("Bring Scavengers to stage 5, control repeat spawns, and strengthen their health and items.", "com.youssef.ScavengerBeforeLoop", "Scavenger Before Loop"); Sprite val = SettingsIcon.Load("ScavengerBeforeLoop.SettingsIcon.png"); if (Object.op_Implicit((Object)(object)val)) { ModSettingsManager.SetModIcon(val, "com.youssef.ScavengerBeforeLoop", "Scavenger Before Loop"); } try { harmony.Patch((MethodBase)AccessTools.Method(typeof(SpawnCard), "DoSpawn", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Plugin), "BeforeSpawn", (Type[])null), new HarmonyMethod(typeof(Plugin), "AfterSpawn", (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "FinishSpawn", (Type[])null), (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(ScavengerItemGranter), "Start", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Plugin), "BeforeItemGrant", (Type[])null), new HarmonyMethod(typeof(Plugin), "AfterItemGrant", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(CharacterBody), "RecalculateStats", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "ChangeScavengerHealth", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); SceneDirector.onPostPopulateSceneServer += ScenePopulated; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Stage 5 Scavengers loaded."); } catch (Exception arg) { harmony.UnpatchSelf(); ((BaseUnityPlugin)this).Logger.LogError((object)$"Stage 5 Scavengers were not applied.\n{arg}"); ((Behaviour)this).enabled = false; } } private void OnDestroy() { SceneDirector.onPostPopulateSceneServer -= ScenePopulated; harmony.UnpatchSelf(); if ((Object)(object)instance == (Object)(object)this) { instance = null; } } private void ScenePopulated(SceneDirector director) { populatedScene = SceneInfo.instance; } private bool IsTargetStage() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Invalid comparison between Unknown and I4 //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown Run val = Run.instance; SceneDef mostRecentSceneDef = SceneCatalog.mostRecentSceneDef; if (!NetworkServer.active || !Object.op_Implicit((Object)(object)val) || val.stageClearCount != 4 || !Object.op_Implicit((Object)(object)SceneInfo.instance) || !Object.op_Implicit((Object)(object)mostRecentSceneDef) || (int)mostRecentSceneDef.sceneType != 1 || mostRecentSceneDef.isFinalStage || !mostRecentSceneDef.validForRandomSelection) { return false; } if ((Object)(object)trackedScene != (Object)(object)SceneInfo.instance) { trackedScene = SceneInfo.instance; spawned = 0; failedAttempts = 0; spawning = false; nextSpawn = 0f; nextAttempt = 0f; rng = new Xoroshiro128Plus(val.seed ^ 0x53434156); } return true; } private void FixedUpdate() { //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Expected O, but got Unknown //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Expected O, but got Unknown //IL_0198: Unknown result type (might be due to invalid IL or missing references) if (!IsTargetStage() || (Object)(object)populatedScene != (Object)(object)trackedScene || Time.fixedTime < nextSpawn || Time.fixedTime < nextAttempt || (spawned > 0 && (onePerStage.Value || TeleporterFinished()))) { return; } nextAttempt = Time.fixedTime + 1f; CharacterBody val = null; foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList) { if (Object.op_Implicit((Object)(object)readOnlyInstances) && readOnlyInstances.isPlayerControlled && Object.op_Implicit((Object)(object)readOnlyInstances.healthComponent) && readOnlyInstances.healthComponent.alive) { val = readOnlyInstances; break; } } if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)DirectorCore.instance)) { return; } if (!Object.op_Implicit((Object)(object)scavenger)) { scavenger = LegacyResourcesAPI.Load<CharacterSpawnCard>("SpawnCards/CharacterSpawnCards/cscScav"); } if (!Object.op_Implicit((Object)(object)scavenger)) { ((BaseUnityPlugin)this).Logger.LogError((object)"The original cscScav spawn card could not be loaded."); ((Behaviour)this).enabled = false; return; } DirectorPlacementRule val2 = new DirectorPlacementRule { placementMode = (PlacementMode)1, position = val.corePosition, minDistance = 30f, maxDistance = 80f, preventOverhead = true }; DirectorSpawnRequest val3 = new DirectorSpawnRequest((SpawnCard)(object)scavenger, val2, rng) { teamIndexOverride = (TeamIndex)2, ignoreTeamMemberLimit = (spawned == 0) }; GameObject val4 = DirectorCore.instance.TrySpawnObject(val3); if (!Object.op_Implicit((Object)(object)val4)) { val2.placementMode = (PlacementMode)4; val4 = DirectorCore.instance.TrySpawnObject(val3); } if (!Object.op_Implicit((Object)(object)val4) && ++failedAttempts == 30) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Still looking for a valid Scavenger spawn point on this stage."); } } private static bool TeleporterFinished() { if (Object.op_Implicit((Object)(object)TeleporterInteraction.instance)) { return TeleporterInteraction.instance.isCharged; } return false; } private static bool IsScavenger(SpawnCard card, DirectorSpawnRequest request) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Invalid comparison between Unknown and I4 if (!Object.op_Implicit((Object)(object)card) || !Object.op_Implicit((Object)(object)card.prefab) || request.teamIndexOverride == (TeamIndex?)1) { return false; } CharacterMaster component = card.prefab.GetComponent<CharacterMaster>(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.bodyPrefab) && ((Object)component.bodyPrefab).name == "ScavBody") { return (int)(((??)request.teamIndexOverride) ?? component.teamIndex) == 2; } return false; } private static bool BeforeSpawn(SpawnCard __instance, Vector3 position, Quaternion rotation, DirectorSpawnRequest spawnRequest, ref SpawnResult __result, out bool __state) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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_0094: Unknown result type (might be due to invalid IL or missing references) __state = false; if (!Object.op_Implicit((Object)(object)instance) || !instance.IsTargetStage() || !IsScavenger(__instance, spawnRequest)) { return true; } if (instance.spawning || (instance.spawned > 0 && (instance.onePerStage.Value || Time.fixedTime < instance.nextSpawn || TeleporterFinished()))) { __result = new SpawnResult { spawnRequest = spawnRequest, position = position, rotation = rotation, success = false }; return false; } instance.spawning = true; __state = true; return true; } private static void AfterSpawn(SpawnResult __result, bool __state) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)instance) && __state && __result.success && Object.op_Implicit((Object)(object)__result.spawnedInstance)) { instance.spawned++; instance.failedAttempts = 0; instance.nextSpawn = Time.fixedTime + (float)instance.spawnInterval.Value; } } private static void FinishSpawn(bool __state) { if (Object.op_Implicit((Object)(object)instance) && __state) { instance.spawning = false; } } private static void BeforeItemGrant(ScavengerItemGranter __instance, out int[] __state) { __state = null; if (!NetworkServer.active || !Object.op_Implicit((Object)(object)instance) || !instance.IsTargetStage()) { return; } Inventory component = ((Component)__instance).GetComponent<Inventory>(); if (Object.op_Implicit((Object)(object)component)) { __state = new int[ItemCatalog.itemCount]; for (int i = 0; i < __state.Length; i++) { __state[i] = component.GetItemCount((ItemIndex)i); } } } private static void AfterItemGrant(ScavengerItemGranter __instance, int[] __state) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Invalid comparison between Unknown and I4 //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Invalid comparison between Unknown and I4 if (__state == null || !Object.op_Implicit((Object)(object)instance)) { return; } Inventory component = ((Component)__instance).GetComponent<Inventory>(); if (!Object.op_Implicit((Object)(object)component)) { return; } int num = (int)(instance.itemMultiplier.Value - 1); for (int i = 0; i < __state.Length; i++) { ItemIndex val = (ItemIndex)i; ItemDef itemDef = ItemCatalog.GetItemDef(val); if (Object.op_Implicit((Object)(object)itemDef) && ((int)itemDef.tier == 0 || (int)itemDef.tier == 1 || (int)itemDef.tier == 2)) { int num2 = component.GetItemCount(val) - __state[i]; if (num2 > 0) { component.GiveItem(val, num2 * num); } } } } private static IEnumerable<CodeInstruction> ChangeScavengerHealth(IEnumerable<CodeInstruction> instructions) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown List<CodeInstruction> list = instructions.ToList(); MethodInfo setter = AccessTools.PropertySetter(typeof(CharacterBody), "maxHealth"); int num = list.FindIndex((CodeInstruction instruction) => CodeInstructionExtensions.Calls(instruction, setter)); if (num < 0) { throw new InvalidOperationException("The maximum-health calculation could not be found."); } CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_0, (object)null); val.labels.AddRange(list[num].labels); list[num].labels.Clear(); list.Insert(num, val); list.Insert(num + 1, new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Plugin), "ScaleScavengerHealth", (Type[])null, (Type[])null))); return list; } private static float ScaleScavengerHealth(float value, CharacterBody body) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)body) || !Object.op_Implicit((Object)(object)Run.instance) || Run.instance.stageClearCount != 4 || body.bodyIndex != BodyCatalog.FindBodyIndex("ScavBody")) { return value; } return value * (float)instance.healthPercent.Value / 100f; } } internal static class SettingsIcon { internal static Sprite Load(string resourceName) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName); if (stream == null) { return null; } byte[] array = new byte[stream.Length]; int num; for (int i = 0; i < array.Length; i += num) { num = stream.Read(array, i, array.Length - i); if (num == 0) { throw new EndOfStreamException(resourceName); } } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(val, array)) { return null; } ((Object)val).name = "ScavengerBeforeLoop settings icon"; return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); } } } namespace LocalTweaks { internal static class PatchTools { internal static MethodInfo Method(string type, string name) { Type type2 = AccessTools.TypeByName(type); if (!(type2 == null)) { return AccessTools.DeclaredMethod(type2, name, (Type[])null, (Type[])null) ?? throw new MissingMethodException(type, name); } throw new TypeLoadException(type); } internal static IEnumerable<CodeInstruction> ReplaceFloat(IEnumerable<CodeInstruction> source, float value, MethodInfo replacement) { List<CodeInstruction> list = source.ToList(); List<CodeInstruction> list2 = list.Where((CodeInstruction x) => x.opcode == OpCodes.Ldc_R4 && x.operand is float num && Math.Abs(num - value) < 1E-06f).ToList(); if (list2.Count != 1) { throw new InvalidOperationException($"Expected one {value} constant, found {list2.Count}."); } list2[0].opcode = OpCodes.Call; list2[0].operand = replacement; return list; } } internal static class TweakSettings { internal static ConfigEntry<int> Slider(ConfigFile file, string section, string name, int value, int min, int max, string description, string guid, string modName) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown ConfigEntry<int> obj = file.Bind<int>(section, name, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<int>(min, max), Array.Empty<object>())); ModSettingsManager.AddOption((BaseOption)new IntSliderOption(obj, new IntSliderConfig { min = min, max = max }), guid, modName); return obj; } internal static ConfigEntry<bool> Checkbox(ConfigFile file, string section, string name, bool value, string description, string guid, string modName) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown ConfigEntry<bool> obj = file.Bind<bool>(section, name, value, description); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(obj), guid, modName); return obj; } } }