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 Wider Blasts v0.2.0
WiderBlasts.dll
Decompiled 15 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using EntityStates; using EntityStates.Engi.EngiBubbleShield; using EntityStates.Merc; using HarmonyLib; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Collections.Generic; using R2API; using RiskOfOptions; using RiskOfOptions.OptionConfigs; using RiskOfOptions.Options; using RoR2; using RoR2.Projectile; using RoR2.Skills; using RoR2.UI; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.Events; using UnityEngine.ResourceManagement.ResourceLocations; [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("WiderBlasts")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.2.0.0")] [assembly: AssemblyInformationalVersion("0.2.0")] [assembly: AssemblyProduct("WiderBlasts")] [assembly: AssemblyTitle("WiderBlasts")] [assembly: AssemblyVersion("0.2.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 WiderBlasts { internal enum MeleeScalingMode { Off, NonPrimary, All } [HarmonyPatch] internal static class BlastHooks { private enum Context { None, Skill, Excluded } private class ScaledMarker : MonoBehaviour { } internal static readonly Dictionary<Type, string> SpecialCases = new Dictionary<Type, string> { { typeof(Deployed), "shield bubble" }, { typeof(Evis), "target radius" }, { typeof(EvisDash), "dash catch radius" } }; private static readonly EntityStateMachine[] stateMachineStack = (EntityStateMachine[])(object)new EntityStateMachine[64]; private static int stateMachineDepth; private static int procDepth; private static int detonateDepth; internal static bool MeleeAllowedForSlot(SkillSlot slot) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 return WiderBlastsPlugin.MeleeScaling.Value switch { MeleeScalingMode.All => true, MeleeScalingMode.NonPrimary => (int)slot > 0, _ => false, }; } internal static CharacterBody ResolveBody(GameObject source) { for (int i = 0; i < 4; i++) { if (!Object.op_Implicit((Object)(object)source)) { break; } ProjectileController component = source.GetComponent<ProjectileController>(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.owner) && (Object)(object)component.owner != (Object)(object)source) { source = component.owner; continue; } GenericOwnership component2 = source.GetComponent<GenericOwnership>(); if (Object.op_Implicit((Object)(object)component2) && Object.op_Implicit((Object)(object)component2.ownerObject) && (Object)(object)component2.ownerObject != (Object)(object)source) { source = component2.ownerObject; continue; } return source.GetComponent<CharacterBody>(); } return null; } private static Context GetContext(out EntityStateMachine machine, out Type stateType) { machine = null; stateType = null; int num = Math.Min(stateMachineDepth, stateMachineStack.Length) - 1; if (num < 0) { return Context.None; } machine = stateMachineStack[num]; if (!Object.op_Implicit((Object)(object)machine) || machine.state == null) { return Context.None; } stateType = ((object)machine.state).GetType(); if (SkillScanner.ExcludedStateTypes.Contains(stateType)) { return Context.Excluded; } if (!SkillScanner.SkillStateTypes.Contains(stateType)) { return Context.None; } return Context.Skill; } private static bool IsSkillTagged(DamageTypeCombo damageType) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 return (damageType.damageSource & 0xF) > 0; } private static void PushStateMachine(EntityStateMachine machine) { if (stateMachineDepth < stateMachineStack.Length) { stateMachineStack[stateMachineDepth] = machine; } stateMachineDepth++; } private static void PopStateMachine() { if (stateMachineDepth > 0) { stateMachineDepth--; if (stateMachineDepth < stateMachineStack.Length) { stateMachineStack[stateMachineDepth] = null; } } } [HarmonyPatch(typeof(EntityStateMachine), "ManagedUpdate")] [HarmonyPrefix] private static void ManagedUpdatePrefix(EntityStateMachine __instance) { PushStateMachine(__instance); } [HarmonyPatch(typeof(EntityStateMachine), "ManagedUpdate")] [HarmonyFinalizer] private static void ManagedUpdateFinalizer() { PopStateMachine(); } [HarmonyPatch(typeof(EntityStateMachine), "ManagedFixedUpdate")] [HarmonyPrefix] private static void ManagedFixedUpdatePrefix(EntityStateMachine __instance) { PushStateMachine(__instance); } [HarmonyPatch(typeof(EntityStateMachine), "ManagedFixedUpdate")] [HarmonyFinalizer] private static void ManagedFixedUpdateFinalizer() { PopStateMachine(); } [HarmonyPatch(typeof(EntityStateMachine), "SetState")] [HarmonyPrefix] private static void SetStatePrefix(EntityStateMachine __instance) { PushStateMachine(__instance); } [HarmonyPatch(typeof(EntityStateMachine), "SetState")] [HarmonyFinalizer] private static void SetStateFinalizer() { PopStateMachine(); } [HarmonyPatch(typeof(EntityStateMachine), "TriggerAnimationEvent")] [HarmonyPrefix] private static void AnimationEventPrefix(EntityStateMachine __instance) { PushStateMachine(__instance); } [HarmonyPatch(typeof(EntityStateMachine), "TriggerAnimationEvent")] [HarmonyFinalizer] private static void AnimationEventFinalizer() { PopStateMachine(); } [HarmonyPatch(typeof(HealthComponent), "TakeDamage", new Type[] { typeof(DamageInfo) })] [HarmonyPrefix] private static void TakeDamagePrefix() { procDepth++; } [HarmonyPatch(typeof(HealthComponent), "TakeDamage", new Type[] { typeof(DamageInfo) })] [HarmonyFinalizer] private static void TakeDamageFinalizer() { procDepth--; } [HarmonyPatch(typeof(GlobalEventManager), "OnHitEnemy")] [HarmonyPrefix] private static void OnHitEnemyPrefix() { procDepth++; } [HarmonyPatch(typeof(GlobalEventManager), "OnHitEnemy")] [HarmonyFinalizer] private static void OnHitEnemyFinalizer() { procDepth--; } [HarmonyPatch(typeof(GlobalEventManager), "OnHitAll")] [HarmonyPrefix] private static void OnHitAllPrefix() { procDepth++; } [HarmonyPatch(typeof(GlobalEventManager), "OnHitAll")] [HarmonyFinalizer] private static void OnHitAllFinalizer() { procDepth--; } [HarmonyPatch(typeof(GlobalEventManager), "HandleCharacterDeath")] [HarmonyPrefix] private static void HandleDeathPrefix() { procDepth++; } [HarmonyPatch(typeof(GlobalEventManager), "HandleCharacterDeath")] [HarmonyFinalizer] private static void HandleDeathFinalizer() { procDepth--; } [HarmonyPatch(typeof(GlobalEventManager), "TriggerCharacterDeathProc")] [HarmonyPrefix] private static void DeathProcPrefix() { procDepth++; } [HarmonyPatch(typeof(GlobalEventManager), "TriggerCharacterDeathProc")] [HarmonyFinalizer] private static void DeathProcFinalizer() { procDepth--; } [HarmonyPatch(typeof(ProjectileExplosion), "DetonateServer")] [HarmonyPrefix] private static void DetonatePrefix(ProjectileExplosion __instance, ProjectileController ___projectileController, ProjectileDamage ___projectileDamage, out float __state) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) __state = -1f; detonateDepth++; if (Object.op_Implicit((Object)(object)___projectileController) && !(__instance.blastRadius <= 0f) && (SkillScanner.ExplosionProjectileIndices.Contains(___projectileController.catalogIndex) || (Object.op_Implicit((Object)(object)___projectileDamage) && IsSkillTagged(___projectileDamage.damageType)))) { float radiusMultiplier = WiderBlastsPlugin.GetRadiusMultiplier(___projectileController.owner); if (radiusMultiplier > 1f) { __state = __instance.blastRadius; __instance.blastRadius *= radiusMultiplier; } } } [HarmonyPatch(typeof(ProjectileExplosion), "DetonateServer")] [HarmonyFinalizer] private static void DetonateFinalizer(ProjectileExplosion __instance, float __state) { detonateDepth--; if (__state >= 0f && Object.op_Implicit((Object)(object)__instance)) { __instance.blastRadius = __state; } } [HarmonyPatch(typeof(BlastAttack), "Fire")] [HarmonyPrefix] private static void BlastFirePrefix(BlastAttack __instance, out float __state) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) __state = -1f; if (detonateDepth > 0 || procDepth > 0) { return; } EntityStateMachine machine; Type stateType; Context context = GetContext(out machine, out stateType); if (context != Context.Excluded && (IsSkillTagged(__instance.damageType) || context == Context.Skill)) { float radiusMultiplier = WiderBlastsPlugin.GetRadiusMultiplier(Object.op_Implicit((Object)(object)__instance.attacker) ? __instance.attacker : (Object.op_Implicit((Object)(object)__instance.inflictor) ? __instance.inflictor : (Object.op_Implicit((Object)(object)machine) ? ((Component)machine).gameObject : null))); if (radiusMultiplier > 1f) { __state = __instance.radius; __instance.radius *= radiusMultiplier; } } } [HarmonyPatch(typeof(BlastAttack), "Fire")] [HarmonyFinalizer] private static void BlastFireFinalizer(BlastAttack __instance, float __state) { if (__state >= 0f) { __instance.radius = __state; } } [HarmonyPatch(typeof(ProjectileController), "Start")] [HarmonyPostfix] private static void ProjectileStartPostfix(ProjectileController __instance) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (SkillScanner.ZoneProjectileIndices.Contains(__instance.catalogIndex)) { float radiusMultiplier = WiderBlastsPlugin.GetRadiusMultiplier(__instance.owner); if (radiusMultiplier > 1f) { Transform transform = ((Component)__instance).transform; transform.localScale *= radiusMultiplier; } } } [HarmonyPatch(typeof(OverlapAttack), "Fire")] [HarmonyPrefix] private static void OverlapFirePrefix(OverlapAttack __instance, out Vector3[] __state) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Invalid comparison between Unknown and I4 //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) __state = null; if (WiderBlastsPlugin.MeleeScaling.Value == MeleeScalingMode.Off || procDepth > 0 || !Object.op_Implicit((Object)(object)__instance.hitBoxGroup) || (Object.op_Implicit((Object)(object)__instance.inflictor) && Object.op_Implicit((Object)(object)__instance.inflictor.GetComponent<ProjectileController>()))) { return; } EntityStateMachine machine; Type stateType; Context context = GetContext(out machine, out stateType); bool flag = IsSkillTagged(__instance.damageType); if (context == Context.Excluded || (!flag && context != Context.Skill) || ((flag ? ((__instance.damageType.damageSource & 0xF) == 1) : (SkillScanner.StateOnlyPrimary.TryGetValue(stateType, out var value) && value)) && WiderBlastsPlugin.MeleeScaling.Value == MeleeScalingMode.NonPrimary)) { return; } float radiusMultiplier = WiderBlastsPlugin.GetRadiusMultiplier(Object.op_Implicit((Object)(object)__instance.attacker) ? __instance.attacker : (Object.op_Implicit((Object)(object)machine) ? ((Component)machine).gameObject : null)); if (radiusMultiplier <= 1f) { return; } HitBox[] hitBoxes = __instance.hitBoxGroup.hitBoxes; __state = (Vector3[])(object)new Vector3[hitBoxes.Length]; for (int i = 0; i < hitBoxes.Length; i++) { if (Object.op_Implicit((Object)(object)hitBoxes[i])) { Transform transform = ((Component)hitBoxes[i]).transform; __state[i] = transform.localScale; transform.localScale = __state[i] * radiusMultiplier; } } } [HarmonyPatch(typeof(OverlapAttack), "Fire")] [HarmonyFinalizer] private static void OverlapFireFinalizer(OverlapAttack __instance, Vector3[] __state) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (__state == null || !Object.op_Implicit((Object)(object)__instance.hitBoxGroup)) { return; } HitBox[] hitBoxes = __instance.hitBoxGroup.hitBoxes; for (int i = 0; i < hitBoxes.Length && i < __state.Length; i++) { if (Object.op_Implicit((Object)(object)hitBoxes[i])) { ((Component)hitBoxes[i]).transform.localScale = __state[i]; } } } [HarmonyPatch(typeof(SphereSearch), "RefreshCandidates")] [HarmonyPrefix] private static void SphereSearchPrefix(SphereSearch __instance, out float __state) { __state = -1f; if (procDepth <= 0 && detonateDepth <= 0 && GetContext(out var machine, out var _) == Context.Skill) { float radiusMultiplier = WiderBlastsPlugin.GetRadiusMultiplier(((Component)machine).gameObject); if (radiusMultiplier > 1f) { __state = __instance.radius; __instance.radius *= radiusMultiplier; } } } [HarmonyPatch(typeof(SphereSearch), "RefreshCandidates")] [HarmonyFinalizer] private static void SphereSearchFinalizer(SphereSearch __instance, float __state) { if (__state >= 0f) { __instance.radius = __state; } } [HarmonyPatch(typeof(Deployed), "FixedUpdate")] [HarmonyPostfix] private static void BubbleDeployedPostfix(Deployed __instance, bool ___hasDeployed) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) if (!___hasDeployed || (Object)(object)((EntityState)__instance).outer == (Object)null) { return; } ChildLocator component = ((Component)((EntityState)__instance).outer).GetComponent<ChildLocator>(); Transform val = (Object.op_Implicit((Object)(object)component) ? component.FindChild(Deployed.childLocatorString) : null); if (Object.op_Implicit((Object)(object)val) && !Object.op_Implicit((Object)(object)((Component)val).GetComponent<ScaledMarker>())) { ((Component)val).gameObject.AddComponent<ScaledMarker>(); float radiusMultiplier = WiderBlastsPlugin.GetRadiusMultiplier(((Component)((EntityState)__instance).outer).gameObject); if (radiusMultiplier > 1f) { val.localScale *= radiusMultiplier; } } } [HarmonyPatch(typeof(Evis), "SearchForTarget")] [HarmonyPrefix] private static void EvisSearchPrefix(Evis __instance, out float __state) { __state = -1f; float radiusMultiplier = WiderBlastsPlugin.GetRadiusMultiplier(Object.op_Implicit((Object)(object)((EntityState)__instance).outer) ? ((Component)((EntityState)__instance).outer).gameObject : null); if (radiusMultiplier > 1f) { __state = Evis.maxRadius; Evis.maxRadius *= radiusMultiplier; } } [HarmonyPatch(typeof(Evis), "SearchForTarget")] [HarmonyFinalizer] private static void EvisSearchFinalizer(float __state) { if (__state >= 0f) { Evis.maxRadius = __state; } } [HarmonyPatch(typeof(EvisDash), "FixedUpdate")] [HarmonyPrefix] private static void EvisDashPrefix(EvisDash __instance, out float __state) { __state = -1f; float radiusMultiplier = WiderBlastsPlugin.GetRadiusMultiplier(Object.op_Implicit((Object)(object)((EntityState)__instance).outer) ? ((Component)((EntityState)__instance).outer).gameObject : null); if (radiusMultiplier > 1f) { __state = EvisDash.overlapSphereRadius; EvisDash.overlapSphereRadius *= radiusMultiplier; } } [HarmonyPatch(typeof(EvisDash), "FixedUpdate")] [HarmonyFinalizer] private static void EvisDashFinalizer(float __state) { if (__state >= 0f) { EvisDash.overlapSphereRadius = __state; } } } [BepInPlugin("com.ewan.WiderBlasts", "Wider Blasts", "0.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class WiderBlastsPlugin : BaseUnityPlugin { public const string PluginGUID = "com.ewan.WiderBlasts"; public const string PluginName = "Wider Blasts"; public const string PluginVersion = "0.2.0"; internal const string TokenPrefix = "EWAN_WIDERBLASTS_"; internal static ManualLogSource Log; internal static ItemDef ItemDef; internal static Sprite IconSprite; internal static ConfigEntry<float> AreaPerStack; internal static ConfigEntry<MeleeScalingMode> MeleeScaling; internal static ConfigEntry<string> ExcludedSkills; private static Harmony harmony; private static LanguageOverlay descriptionOverlay; private void Awake() { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; AreaPerStack = ((BaseUnityPlugin)this).Config.Bind<float>("Item", "Area Per Stack", 0.1f, "Extra ground area covered by skill explosions, per stack of the item. 0.1 = +10% area per stack. Area grows linearly with stacks; the radius grows by the square root of that (+10% area is about +4.9% radius)."); AreaPerStack.SettingChanged += delegate { UpdateDescriptionText(); }; MeleeScaling = ((BaseUnityPlugin)this).Config.Bind<MeleeScalingMode>("Item", "Melee Hitboxes", MeleeScalingMode.NonPrimary, "Which melee swing hitboxes the item grows. NonPrimary = Secondary/Utility/Special skills only."); ExcludedSkills = ((BaseUnityPlugin)this).Config.Bind<string>("Item", "Excluded Skills", "Ascent Protocol", "Comma-separated skill names the item never affects. Takes effect after restarting the game."); IconSprite = MakeIconSprite(); CreateItem(); harmony = new Harmony("com.ewan.WiderBlasts"); harmony.PatchAll(typeof(BlastHooks)); RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(OnGameLoaded)); if (Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions")) { try { OptionsMenu.Init(); } catch (Exception arg) { Log.LogWarning((object)$"Risk Of Options setup failed: {arg}"); } } Log.LogInfo((object)"Wider Blasts v0.2.0 initialized"); } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } private void OnGameLoaded() { try { SkillScanner.Scan(); } catch (Exception arg) { Log.LogError((object)$"Skill scan failed: {arg}"); return; } string text = SkillScanner.BuildPlainReport(); Log.LogInfo((object)("Affected skills:\n" + text)); try { File.WriteAllText(Path.Combine(Paths.ConfigPath, "com.ewan.WiderBlasts.AffectedSkills.txt"), text); } catch (Exception ex) { Log.LogWarning((object)("Could not write affected-skills file: " + ex.Message)); } if (Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions")) { try { OptionsMenu.AddSkillList(); } catch (Exception arg2) { Log.LogWarning((object)$"Risk Of Options skill list failed: {arg2}"); } } } internal static float GetRadiusMultiplier(GameObject source) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 //IL_0054: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)source) || !Object.op_Implicit((Object)(object)ItemDef) || (int)ItemDef.itemIndex == -1) { return 1f; } CharacterBody val = BlastHooks.ResolveBody(source); Inventory val2 = (Object.op_Implicit((Object)(object)val) ? val.inventory : null); if (!Object.op_Implicit((Object)(object)val2)) { return 1f; } int itemCountEffective = val2.GetItemCountEffective(ItemDef.itemIndex); if (itemCountEffective <= 0) { return 1f; } return Mathf.Sqrt(1f + AreaPerStack.Value * (float)itemCountEffective); } private static void CreateItem() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown ItemTierDef val = LoadTierDef(); LanguageAPI.Add("EWAN_WIDERBLASTS_ITEM_NAME", "Shockwave Lens"); LanguageAPI.Add("EWAN_WIDERBLASTS_ITEM_PICKUP", "Your skill explosions are bigger."); LanguageAPI.Add("EWAN_WIDERBLASTS_ITEM_LORE", "A cracked lens that bends every blast outward."); UpdateDescriptionText(); ItemDisplayRuleDict val2 = new ItemDisplayRuleDict((ItemDisplayRule[])null); CustomItem val3 = new CustomItem("WiderBlastsLens", "EWAN_WIDERBLASTS_ITEM_NAME", "EWAN_WIDERBLASTS_ITEM_DESC", "EWAN_WIDERBLASTS_ITEM_LORE", "EWAN_WIDERBLASTS_ITEM_PICKUP", IconSprite, LoadPickupModel(), (ItemTier)(Object.op_Implicit((Object)(object)val) ? 1000 : 0), (ItemTag[])(object)new ItemTag[2] { (ItemTag)1, (ItemTag)3 }, true, false, (UnlockableDef)null, val2, val); ItemDef = val3.ItemDef; ItemAPI.Add(val3); } private static void UpdateDescriptionText() { string text = (AreaPerStack.Value * 100f).ToString("0.#"); string text2 = "Increases the <style=cIsDamage>area</style> of your <style=cIsDamage>skill explosions</style> by <style=cIsDamage>" + text + "%</style> <style=cStack>(+" + text + "% per stack)</style>."; LanguageOverlay obj = descriptionOverlay; if (obj != null) { obj.Remove(); } descriptionOverlay = LanguageAPI.AddOverlay("EWAN_WIDERBLASTS_ITEM_DESC", text2); } private static ItemTierDef LoadTierDef() { string[] array = new string[2] { "Assets/RoR2/Base/Common/ItemTierDefs/Tier1Def.asset", "RoR2/Base/Common/Tier1Def.asset" }; for (int i = 0; i < array.Length; i++) { ItemTierDef val = WiderBlastsPlugin.TryLoad<ItemTierDef>(array[i]); if (Object.op_Implicit((Object)(object)val)) { return val; } } Log.LogWarning((object)"Could not load Tier1Def; falling back to R2API's tier lookup."); return null; } private static GameObject LoadPickupModel() { return WiderBlastsPlugin.TryLoad<GameObject>("Assets/RoR2/Base/MiscPickups/Mystery/PickupMystery.prefab") ?? WiderBlastsPlugin.TryLoad<GameObject>("RoR2/Base/Mystery/PickupMystery.prefab"); } internal static T TryLoad<T>(string key) where T : Object { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) try { IList<IResourceLocation> list = Addressables.LoadResourceLocationsAsync((object)key, typeof(T)).WaitForCompletion(); if (list == null || list.Count == 0) { return default(T); } return Addressables.LoadAssetAsync<T>((object)key).WaitForCompletion(); } catch (Exception) { return default(T); } } private static Sprite MakeIconSprite() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(128, 128, (TextureFormat)4, false); Color val2 = default(Color); ((Color)(ref val2))..ctor(1f, 0.62f, 0.2f); Color val3 = default(Color); ((Color)(ref val3))..ctor(1f, 0.9f, 0.7f); float num = 64f; for (int i = 0; i < 128; i++) { for (int j = 0; j < 128; j++) { float num2 = Mathf.Sqrt(((float)j + 0.5f - num) * ((float)j + 0.5f - num) + ((float)i + 0.5f - num) * ((float)i + 0.5f - num)) / num; Color val4 = Color.clear; if (num2 < 0.2f) { val4 = Color.Lerp(val3, val2, num2 / 0.2f); } else { float[] array = new float[3] { 0.4f, 0.62f, 0.84f }; for (int k = 0; k < array.Length; k++) { float num3 = Mathf.Abs(num2 - array[k]); float num4 = 0.055f - (float)k * 0.01f; if (num3 < num4) { float num5 = (1f - num3 / num4) * (1f - (float)k * 0.25f); ((Color)(ref val4))..ctor(val2.r, val2.g, val2.b, Mathf.Max(val4.a, num5)); } } } val.SetPixel(j, i, val4); } } val.Apply(); return Sprite.Create(val, new Rect(0f, 0f, 128f, 128f), new Vector2(0.5f, 0.5f)); } } internal static class OptionsMenu { private class SurvivorEntry { public SkillScanner.SurvivorInfo Survivor; public string NameToken; public string BodyToken; public LanguageOverlay NameOverlay; public LanguageOverlay BodyOverlay; } private const string Category = "Affected Skills"; private static readonly List<SurvivorEntry> entries = new List<SurvivorEntry>(); [MethodImpl(MethodImplOptions.NoInlining)] internal static void Init() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Expected O, but got Unknown //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Expected O, but got Unknown //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Expected O, but got Unknown //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Expected O, but got Unknown ModSettingsManager.SetModDescription("Adds the Shockwave Lens, a white item that makes skill areas bigger.\n\nScanning skills... open this menu again after the game finishes loading.", "com.ewan.WiderBlasts", "Wider Blasts"); if (Object.op_Implicit((Object)(object)WiderBlastsPlugin.IconSprite)) { ModSettingsManager.SetModIcon(WiderBlastsPlugin.IconSprite, "com.ewan.WiderBlasts", "Wider Blasts"); } ModSettingsManager.AddOption((BaseOption)new StepSliderOption(WiderBlastsPlugin.AreaPerStack, new StepSliderConfig { min = 0.01f, max = 0.5f, increment = 0.01f, FormatString = "{0:P0}", category = "Item", name = "Area Per Stack", description = "Extra ground area covered by skill areas, per stack. Default 10% (about +4.9% radius for one stack)." }), "com.ewan.WiderBlasts", "Wider Blasts"); ModSettingsManager.AddOption((BaseOption)new ChoiceOption((ConfigEntryBase)(object)WiderBlastsPlugin.MeleeScaling, new ChoiceConfig { category = "Item", name = "Melee Hitboxes", description = "Which melee swing hitboxes the item grows.\n\n<style=cIsDamage>NonPrimary</style>: Secondary, Utility and Special skills (default).\n<style=cIsDamage>All</style>: primaries too.\n<style=cIsDamage>Off</style>: no melee scaling." }), "com.ewan.WiderBlasts", "Wider Blasts"); ModSettingsManager.AddOption((BaseOption)new StringInputFieldOption(WiderBlastsPlugin.ExcludedSkills, new InputFieldConfig { category = "Item", name = "Excluded Skills", description = "Comma-separated skill names the item never affects, e.g. \"Ascent Protocol, Abduct\". Needs a game restart.", submitOn = (SubmitEnum)6, restartRequired = true }), "com.ewan.WiderBlasts", "Wider Blasts"); WiderBlastsPlugin.MeleeScaling.SettingChanged += delegate { Refresh(); }; } [MethodImpl(MethodImplOptions.NoInlining)] internal static void AddSkillList() { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Expected O, but got Unknown HashSet<string> hashSet = new HashSet<string>(); foreach (SkillScanner.SurvivorInfo result in SkillScanner.Results) { string text = result.Name; int num = 2; while (!hashSet.Add(text)) { text = result.Name + " " + num; num++; } SurvivorEntry entry = new SurvivorEntry { Survivor = result, NameToken = "EWAN_WIDERBLASTS_LIST_NAME_" + hashSet.Count, BodyToken = "EWAN_WIDERBLASTS_LIST_BODY_" + hashSet.Count }; entries.Add(entry); GenericButtonOption val = new GenericButtonOption(text, "Affected Skills", "", "Show", (UnityAction)delegate { ShowDialog(entry); }); ModSettingsManager.AddOption((BaseOption)val, "com.ewan.WiderBlasts", "Wider Blasts", entry.NameToken, entry.BodyToken); LanguageAPI.Add(val.GetButtonLabelToken(), "Show"); } Refresh(); } private static void Refresh() { if (SkillScanner.Results.Count > 0) { ModSettingsManager.SetModDescription(SkillScanner.BuildSummary(), "com.ewan.WiderBlasts", "Wider Blasts"); } foreach (SurvivorEntry entry in entries) { LanguageOverlay nameOverlay = entry.NameOverlay; if (nameOverlay != null) { nameOverlay.Remove(); } LanguageOverlay bodyOverlay = entry.BodyOverlay; if (bodyOverlay != null) { bodyOverlay.Remove(); } entry.NameOverlay = LanguageAPI.AddOverlay(entry.NameToken, $"{entry.Survivor.Name} ({entry.Survivor.AffectedCount} affected)"); entry.BodyOverlay = LanguageAPI.AddOverlay(entry.BodyToken, SkillScanner.BuildSurvivorText(entry.Survivor)); } } private static void ShowDialog(SurvivorEntry entry) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) SimpleDialogBox obj = SimpleDialogBox.Create((MPEventSystem)null); obj.headerToken = new TokenParamsPair(entry.NameToken, Array.Empty<object>()); obj.descriptionToken = new TokenParamsPair(entry.BodyToken, Array.Empty<object>()); obj.AddCancelButton(CommonLanguageTokens.ok, Array.Empty<object>()); } } internal static class SkillScanner { internal class SkillInfo { public string Slot; public string Name; public SkillSlot SlotEnum; public bool MainSlot; public bool Excluded; public readonly List<string> Explosions = new List<string>(); public readonly List<string> Specials = new List<string>(); public bool BlastInCode; public bool Zone; public bool AreaSearch; public bool Melee; public bool RawOverlap; public readonly HashSet<Type> States = new HashSet<Type>(); public readonly HashSet<int> ExplosionProjectiles = new HashSet<int>(); public readonly HashSet<int> ZoneProjectiles = new HashSet<int>(); public bool MeleeScaled { get { //IL_0009: Unknown result type (might be due to invalid IL or missing references) if (Melee) { return BlastHooks.MeleeAllowedForSlot(SlotEnum); } return false; } } public bool Affected { get { if (!Excluded) { if (Explosions.Count <= 0 && Specials.Count <= 0 && !BlastInCode && !Zone && !AreaSearch) { return MeleeScaled; } return true; } return false; } } public bool HasUnscaledArea { get { if (!Affected) { if (!Melee && !RawOverlap && Explosions.Count <= 0 && Specials.Count <= 0 && !BlastInCode && !Zone) { return AreaSearch; } return true; } return false; } } public bool Visible { get { if (!MainSlot && !Affected) { return HasUnscaledArea; } return true; } } } internal class SurvivorInfo { public string Name; public readonly List<SkillInfo> Skills = new List<SkillInfo>(); public int AffectedCount => Skills.Count((SkillInfo s) => s.Affected); } internal static readonly HashSet<int> ExplosionProjectileIndices = new HashSet<int>(); internal static readonly HashSet<int> ZoneProjectileIndices = new HashSet<int>(); internal static readonly HashSet<Type> SkillStateTypes = new HashSet<Type>(); internal static readonly HashSet<Type> ExcludedStateTypes = new HashSet<Type>(); internal static readonly Dictionary<Type, bool> StateOnlyPrimary = new Dictionary<Type, bool>(); internal static readonly List<SurvivorInfo> Results = new List<SurvivorInfo>(); private const int MaxStatesPerSkill = 64; private const int MaxPrefabDepth = 4; private const int MaxCallDepth = 2; private static readonly Dictionary<Assembly, ModuleDefinition> modules = new Dictionary<Assembly, ModuleDefinition>(); private static readonly Dictionary<string, Assembly> assembliesByName = new Dictionary<string, Assembly>(); private static Assembly ror2Assembly; private static HashSet<string> excludedNames; private static SkillInfo current; private static Queue<Type> stateQueue; private static HashSet<Type> visitedStates; private static HashSet<GameObject> visitedPrefabs; private static HashSet<MethodDefinition> visitedMethods; private static HashSet<Type> excludedStates; private static bool suppressRawOverlap; internal static void Scan() { ror2Assembly = typeof(BlastAttack).Assembly; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { assembliesByName[assembly.GetName().Name] = assembly; } excludedNames = new HashSet<string>(from s in WiderBlastsPlugin.ExcludedSkills.Value.Split(',') select s.Trim() into s where s.Length > 0 select s, StringComparer.OrdinalIgnoreCase); Results.Clear(); try { foreach (SurvivorDef orderedSurvivorDef in SurvivorCatalog.orderedSurvivorDefs) { if (Object.op_Implicit((Object)(object)orderedSurvivorDef) && !orderedSurvivorDef.hidden && Object.op_Implicit((Object)(object)orderedSurvivorDef.bodyPrefab)) { try { Results.Add(ScanSurvivor(orderedSurvivorDef)); } catch (Exception ex) { WiderBlastsPlugin.Log.LogWarning((object)("Skipped survivor " + orderedSurvivorDef.cachedName + ": " + ex.Message)); } } } } finally { foreach (ModuleDefinition value in modules.Values) { if (value != null) { value.Dispose(); } } modules.Clear(); } WiderBlastsPlugin.Log.LogInfo((object)($"Scanned {Results.Count} survivors: {SkillStateTypes.Count} skill states, " + $"{ExplosionProjectileIndices.Count} exploding and {ZoneProjectileIndices.Count} zone projectiles, {ExcludedStateTypes.Count} excluded states.")); } private unsafe static SurvivorInfo ScanSurvivor(SurvivorDef survivor) { //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Invalid comparison between Unknown and I4 //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Invalid comparison between Unknown and I4 GameObject bodyPrefab = survivor.bodyPrefab; SurvivorInfo survivorInfo = new SurvivorInfo { Name = Resolve(survivor.displayNameToken, ((Object)bodyPrefab).name) }; excludedStates = new HashSet<Type> { typeof(Uninitialized), typeof(Idle), typeof(GenericCharacterMain) }; EntityStateMachine[] components = bodyPrefab.GetComponents<EntityStateMachine>(); foreach (EntityStateMachine val in components) { AddIfNotNull(excludedStates, ((SerializableEntityStateType)(ref val.initialStateType)).stateType); AddIfNotNull(excludedStates, ((SerializableEntityStateType)(ref val.mainStateType)).stateType); } SkillLocator component = bodyPrefab.GetComponent<SkillLocator>(); HashSet<SkillDef> hashSet = new HashSet<SkillDef>(); GenericSkill[] components2 = bodyPrefab.GetComponents<GenericSkill>(); foreach (GenericSkill val2 in components2) { SkillFamily skillFamily = val2.skillFamily; if (!Object.op_Implicit((Object)(object)skillFamily)) { continue; } SkillSlot val3 = (SkillSlot)((!Object.op_Implicit((Object)(object)component)) ? (-1) : ((int)component.FindSkillSlot(val2))); string slot = (((int)val3 != -1) ? ((object)(*(SkillSlot*)(&val3))/*cast due to .constrained prefix*/).ToString() : (string.IsNullOrEmpty(val2.skillName) ? "Other" : val2.skillName)); Variant[] variants = skillFamily.variants; for (int j = 0; j < variants.Length; j++) { SkillDef skillDef = variants[j].skillDef; if (Object.op_Implicit((Object)(object)skillDef) && hashSet.Add(skillDef)) { SkillInfo skillInfo = new SkillInfo { Slot = slot, SlotEnum = val3, MainSlot = ((int)val3 != -1), Name = Resolve(skillDef.skillNameToken, skillDef.skillName) }; skillInfo.Excluded = excludedNames.Contains(skillInfo.Name) || excludedNames.Contains(skillDef.skillName ?? "") || excludedNames.Contains(skillDef.skillNameToken ?? ""); try { ScanSkill(skillDef, skillInfo); } catch (Exception ex) { WiderBlastsPlugin.Log.LogWarning((object)("Error scanning " + survivorInfo.Name + " / " + skillInfo.Name + ": " + ex.Message)); } Register(skillInfo); survivorInfo.Skills.Add(skillInfo); } } } return survivorInfo; } private static void Register(SkillInfo skill) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Invalid comparison between Unknown and I4 if (skill.Excluded) { ExcludedStateTypes.UnionWith(skill.States); return; } SkillStateTypes.UnionWith(skill.States); ExplosionProjectileIndices.UnionWith(skill.ExplosionProjectiles); ZoneProjectileIndices.UnionWith(skill.ZoneProjectiles); bool flag = (int)skill.SlotEnum == 0; foreach (Type state in skill.States) { StateOnlyPrimary[state] = (!StateOnlyPrimary.TryGetValue(state, out var value) || value) && flag; } } private static void ScanSkill(SkillDef skillDef, SkillInfo skill) { current = skill; stateQueue = new Queue<Type>(); visitedStates = new HashSet<Type>(); visitedPrefabs = new HashSet<GameObject>(); visitedMethods = new HashSet<MethodDefinition>(); foreach (FieldInfo item in AllFields(((object)skillDef).GetType(), typeof(ScriptableObject))) { if (!item.IsStatic) { HandleValue(item.GetValue(skillDef), allowNested: true); } } while (stateQueue.Count > 0 && visitedStates.Count < 64) { Type type = stateQueue.Dequeue(); if (visitedStates.Add(type) && !excludedStates.Contains(type)) { skill.States.Add(type); if (BlastHooks.SpecialCases.TryGetValue(type, out var value) && !skill.Specials.Contains(value)) { skill.Specials.Add(value); } ScanStateFields(type); ScanStateCode(type); } } current = null; } private static void EnqueueState(Type type) { if (type != null && !type.IsAbstract && typeof(EntityState).IsAssignableFrom(type) && !visitedStates.Contains(type)) { stateQueue.Enqueue(type); } } private static void ScanStateFields(Type stateType) { EntityState val = null; try { val = EntityStateCatalog.InstantiateState(stateType); } catch (Exception) { } foreach (FieldInfo item in AllFields(stateType, typeof(EntityState))) { if (!item.DeclaringType.ContainsGenericParameters) { object value; try { value = (item.IsStatic ? item.GetValue(null) : ((val != null) ? item.GetValue(val) : null)); } catch (Exception) { continue; } HandleValue(value, allowNested: false); } } } private static void HandleValue(object value, bool allowNested) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_008f: 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) if (value == null) { return; } GameObject val = (GameObject)((value is GameObject) ? value : null); if (val == null) { if (!(value is SerializableEntityStateType val2)) { if (!(value is Type type)) { if (!(value is GameObject[] array)) { if (value is SerializableEntityStateType[] array2) { SerializableEntityStateType[] array3 = array2; for (int i = 0; i < array3.Length; i++) { SerializableEntityStateType val3 = array3[i]; EnqueueState(((SerializableEntityStateType)(ref val3)).stateType); } } else { if (!allowNested || !(value is Array array4)) { return; } foreach (object item in array4) { if (item != null && !(item is Object)) { FieldInfo[] fields = item.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < fields.Length; i++) { HandleValue(fields[i].GetValue(item), allowNested: false); } } } } } else { GameObject[] array5 = array; for (int i = 0; i < array5.Length; i++) { ScanPrefab(array5[i], 0); } } } else { EnqueueState(type); } } else { EnqueueState(((SerializableEntityStateType)(ref val2)).stateType); } } else { ScanPrefab(val, 0); } } private static void ScanPrefab(GameObject prefab, int depth) { if (!Object.op_Implicit((Object)(object)prefab) || depth > 4 || !visitedPrefabs.Add(prefab)) { return; } ProjectileController component = prefab.GetComponent<ProjectileController>(); if (!Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)prefab.GetComponent<CharacterBody>())) { return; } int num = (Object.op_Implicit((Object)(object)component) ? ProjectileCatalog.GetProjectileIndex(component) : (-1)); ProjectileExplosion[] componentsInChildren = prefab.GetComponentsInChildren<ProjectileExplosion>(true); foreach (ProjectileExplosion val in componentsInChildren) { if (val.blastRadius > 0f && Object.op_Implicit((Object)(object)((Component)val).GetComponent<ProjectileDamage>())) { string item = $"{val.blastRadius:0.#} m explosion"; if (!current.Explosions.Contains(item)) { current.Explosions.Add(item); } if (num >= 0) { current.ExplosionProjectiles.Add(num); } } } bool flag = Object.op_Implicit((Object)(object)prefab.GetComponentInChildren<ProjectileDotZone>(true)); if (!flag && Object.op_Implicit((Object)(object)prefab.GetComponentInChildren<ProjectileOverlapAttack>(true))) { ProjectileSimple component2 = prefab.GetComponent<ProjectileSimple>(); flag = Object.op_Implicit((Object)(object)component2) && component2.desiredForwardSpeed <= 0f; } if (flag && num >= 0) { current.Zone = true; current.ZoneProjectiles.Add(num); } EntityStateMachine[] componentsInChildren2 = prefab.GetComponentsInChildren<EntityStateMachine>(true); foreach (EntityStateMachine obj in componentsInChildren2) { EnqueueState(((SerializableEntityStateType)(ref obj.initialStateType)).stateType); EnqueueState(((SerializableEntityStateType)(ref obj.mainStateType)).stateType); } MonoBehaviour[] componentsInChildren3 = prefab.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val2 in componentsInChildren3) { if (!Object.op_Implicit((Object)(object)val2)) { continue; } foreach (FieldInfo item2 in AllFields(((object)val2).GetType(), typeof(MonoBehaviour))) { if (!item2.IsStatic && !(item2.FieldType != typeof(GameObject))) { object? value = item2.GetValue(val2); GameObject val3 = (GameObject)((value is GameObject) ? value : null); if (Object.op_Implicit((Object)(object)val3) && Object.op_Implicit((Object)(object)val3.GetComponent<ProjectileController>())) { ScanPrefab(val3, depth + 1); } } } } } private static void ScanStateCode(Type stateType) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) suppressRawOverlap = BlastHooks.SpecialCases.ContainsKey(stateType); Type type = stateType; while (type != null && type != typeof(EntityState)) { if (!(type == typeof(BaseState)) && !(type == typeof(BaseSkillState))) { TypeDefinition typeDefinition = GetTypeDefinition(type); if (typeDefinition != null) { Enumerator<MethodDefinition> enumerator = typeDefinition.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { ScanMethod(enumerator.Current, 0); } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } } type = type.BaseType; } suppressRawOverlap = false; } private static void ScanMethod(MethodDefinition method, int depth) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (method == null || !method.HasBody || !visitedMethods.Add(method)) { return; } Enumerator<Instruction> enumerator = method.Body.Instructions.GetEnumerator(); try { while (enumerator.MoveNext()) { Instruction ins = enumerator.Current; try { ScanInstruction(method, ins, depth); } catch (Exception) { } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } private static void ScanInstruction(MethodDefinition method, Instruction ins, int depth) { //IL_003a: 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_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) object operand = ins.Operand; MethodReference val = (MethodReference)((operand is MethodReference) ? operand : null); if (val == null) { FieldReference val2 = (FieldReference)((operand is FieldReference) ? operand : null); if (val2 == null) { TypeReference val3 = (TypeReference)((operand is TypeReference) ? operand : null); if (val3 != null && ins.OpCode == OpCodes.Ldtoken) { EnqueueState(ResolveType(val3)); } } else { if (!(ins.OpCode == OpCodes.Ldsfld)) { return; } string fullName = ((MemberReference)val2.FieldType).FullName; if (!(fullName != "UnityEngine.GameObject") || !(fullName != "UnityEngine.GameObject[]")) { Type type = ResolveType(((MemberReference)val2).DeclaringType); FieldInfo fieldInfo = type?.GetField(((MemberReference)val2).Name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo != null && !type.ContainsGenericParameters) { HandleValue(fieldInfo.GetValue(null), allowNested: false); } } } return; } string fullName2 = ((MemberReference)((MemberReference)val).DeclaringType).FullName; if (ins.OpCode == OpCodes.Newobj) { switch (fullName2) { case "RoR2.BlastAttack": current.BlastInCode = true; return; case "RoR2.SphereSearch": current.AreaSearch = true; return; case "RoR2.OverlapAttack": current.Melee = true; return; } Type type2 = ResolveType(((MemberReference)val).DeclaringType); if (type2 != null && typeof(EntityState).IsAssignableFrom(type2)) { EnqueueState(type2); return; } } if (fullName2 == "RoR2.BlastAttack" && ((MemberReference)val).Name == "Fire") { current.BlastInCode = true; } else if (((MemberReference)val).Name == "InitMeleeOverlap") { current.Melee = true; } else if ((fullName2 == "UnityEngine.Physics" || fullName2 == "RoR2.HGPhysics") && ((MemberReference)val).Name.StartsWith("OverlapSphere")) { current.RawOverlap |= !suppressRawOverlap; } else if (depth < 2 && (object)((MemberReference)val).DeclaringType.Scope == ((MemberReference)method).Module && (((AssemblyNameReference)((MemberReference)method).Module.Assembly.Name).Name != ror2Assembly.GetName().Name || OuterNamespace(((MemberReference)val).DeclaringType).StartsWith("EntityStates"))) { MethodDefinition val4 = val.Resolve(); if (val4 != null && !IsEntityStateType(val4.DeclaringType)) { ScanMethod(val4, depth + 1); } } } private static string OuterNamespace(TypeReference type) { while (((MemberReference)type).DeclaringType != null) { type = ((MemberReference)type).DeclaringType; } return type.Namespace ?? ""; } private static bool IsEntityStateType(TypeDefinition typeDef) { Type type = ResolveType((TypeReference)(object)typeDef); if (type != null) { return typeof(EntityState).IsAssignableFrom(type); } return false; } private static TypeDefinition GetTypeDefinition(Type type) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown Assembly assembly = type.Assembly; if (!modules.TryGetValue(assembly, out var value)) { value = null; try { string text = assembly.Location; if (string.IsNullOrEmpty(text)) { text = Path.Combine(Paths.ManagedPath, assembly.GetName().Name + ".dll"); } if (File.Exists(text)) { value = ModuleDefinition.ReadModule(text, new ReaderParameters { ReadingMode = (ReadingMode)2 }); } else { WiderBlastsPlugin.Log.LogWarning((object)("No file for " + assembly.GetName().Name + "; skill code in it is not scanned.")); } } catch (Exception ex) { WiderBlastsPlugin.Log.LogDebug((object)("Cannot read " + assembly.GetName().Name + ": " + ex.Message)); } modules[assembly] = value; } if (value == null) { return null; } Type type2 = (type.IsGenericType ? type.GetGenericTypeDefinition() : type); return value.GetType(type2.FullName.Replace('+', '/')); } private static Type ResolveType(TypeReference typeRef) { if (typeRef == null) { return null; } GenericInstanceType val = (GenericInstanceType)(object)((typeRef is GenericInstanceType) ? typeRef : null); if (val != null) { typeRef = ((TypeSpecification)val).ElementType; } IMetadataScope scope = typeRef.Scope; ModuleDefinition val2 = (ModuleDefinition)(object)((scope is ModuleDefinition) ? scope : null); string text; if (val2 == null) { AssemblyNameReference val3 = (AssemblyNameReference)(object)((scope is AssemblyNameReference) ? scope : null); text = ((val3 == null) ? null : val3.Name); } else { text = ((AssemblyNameReference)val2.Assembly.Name).Name; } string text2 = text; if (text2 == null || !assembliesByName.TryGetValue(text2, out var value)) { return null; } return value.GetType(((MemberReference)typeRef).FullName.Replace('/', '+'), throwOnError: false); } private static IEnumerable<FieldInfo> AllFields(Type type, Type stopAt) { Type t = type; while (t != null && t != stopAt && t != typeof(object)) { FieldInfo[] fields = t.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < fields.Length; i++) { yield return fields[i]; } t = t.BaseType; } } private static void AddIfNotNull(HashSet<Type> set, Type type) { if (type != null) { set.Add(type); } } private static string Resolve(string token, string fallback) { if (string.IsNullOrEmpty(token)) { return fallback; } string text = Language.GetString(token); if (!string.IsNullOrEmpty(text) && !(text == token)) { return text; } if (!string.IsNullOrEmpty(fallback)) { return fallback; } return token; } internal static string BuildSummary() { int num = Results.Count((SurvivorInfo r) => r.AffectedCount > 0); int num2 = Results.Sum((SurvivorInfo r) => r.AffectedCount); return "Adds the <style=cIsDamage>Shockwave Lens</style>, a white item that makes skill areas bigger: explosions, damage zones, area searches and (optionally) melee hitboxes.\n\n" + $"<style=cIsDamage>{num2}</style> skills across <style=cIsDamage>{num}</style> of {Results.Count} survivors are affected.\n" + "Open the <style=cIsUtility>Affected Skills</style> tab and hover a survivor to see which skills."; } internal static string BuildSurvivorText(SurvivorInfo survivor) { StringBuilder stringBuilder = new StringBuilder(); List<SkillInfo> list = survivor.Skills.Where((SkillInfo s) => s.Affected).ToList(); List<SkillInfo> list2 = survivor.Skills.Where((SkillInfo s) => s.HasUnscaledArea).ToList(); List<SkillInfo> list3 = survivor.Skills.Where((SkillInfo s) => s.Visible && !s.Affected && !s.HasUnscaledArea).ToList(); stringBuilder.Append("<style=cIsDamage>Bigger with Shockwave Lens:</style>\n"); if (list.Count == 0) { stringBuilder.Append(" (none)\n"); } foreach (SkillInfo item in list) { stringBuilder.Append(" " + item.Slot + ": " + item.Name + " <style=cStack>" + Detail(item) + "</style>\n"); } if (list2.Count > 0) { stringBuilder.Append("\n<style=cIsUtility>Has an area, but not scaled:</style>\n"); foreach (SkillInfo item2 in list2) { stringBuilder.Append(" " + item2.Slot + ": " + item2.Name + " <style=cStack>" + UnscaledReason(item2) + "</style>\n"); } } if (list3.Count > 0) { stringBuilder.Append("\n<style=cStack>No area: "); stringBuilder.Append(string.Join(", ", list3.Select((SkillInfo s) => s.Name))); stringBuilder.Append("</style>"); } return stringBuilder.ToString(); } private static string Detail(SkillInfo s) { List<string> list = new List<string>(s.Explosions); list.AddRange(s.Specials); if (s.BlastInCode) { list.Add("blast in skill code"); } if (s.Zone) { list.Add("damage zone"); } if (s.AreaSearch) { list.Add("area search"); } if (s.MeleeScaled) { list.Add("melee hitbox"); } return string.Join(", ", list); } private static string UnscaledReason(SkillInfo s) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (s.Excluded) { return "excluded in settings"; } if (s.Melee) { if ((int)s.SlotEnum != 0 || WiderBlastsPlugin.MeleeScaling.Value != MeleeScalingMode.NonPrimary) { return "melee hitbox (off in settings)"; } return "primary melee hitbox (off in settings)"; } return "uses a sphere check this mod can't scale yet"; } internal static string BuildPlainReport() { StringBuilder stringBuilder = new StringBuilder(); foreach (SurvivorInfo result in Results) { stringBuilder.AppendLine($"{result.Name} ({result.AffectedCount} affected)"); foreach (SkillInfo item in result.Skills.Where((SkillInfo s) => s.Visible)) { if (item.Affected) { stringBuilder.AppendLine(" AFFECTED " + item.Slot + ": " + item.Name + " [" + Detail(item) + "]"); } else if (item.HasUnscaledArea) { stringBuilder.AppendLine(" NOT SCALED " + item.Slot + ": " + item.Name + " [" + UnscaledReason(item) + "]"); } else { stringBuilder.AppendLine(" - " + item.Slot + ": " + item.Name); } } } return stringBuilder.ToString(); } } }