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 EnemySizeRandomizer v1.5.3
BepInEx/plugins/EnemySizeRandomizer.dll
Decompiled 2 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using ScalerCore; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("EnemySizeRandomizer")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("EnemySizeRandomizer")] [assembly: AssemblyTitle("EnemySizeRandomizer")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [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 EnemySizeRandomizer { [BepInPlugin("Grungler.EnemySizeRandomizer", "Enemy Size Randomizer", "1.5.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class EnemySizeRandomizerPlugin : BaseUnityPlugin { private class TimerField { public object Owner; public FieldInfo Field; } private class HuntsmanData { public EnemyHunter Hunter; public Vector3 OriginalGunTipPosition; public Vector3 OriginalGunAimPosition; public bool HasGunTip; public bool HasGunAim; } private class EnemyData { public EnemyParent Enemy; public ScaleController Controller; public float Size; public float Speed; public Animator[] Animators; public AudioSource[] AudioSources; public EnemyRigidbody EnemyRigidbody; public float OriginalPositionSpeedChase; public float OriginalPositionSpeedIdle; public float OriginalRotationSpeedChase; public float OriginalRotationSpeedIdle; public GrabForce OriginalGrabForce; public bool HasOriginalRigidbodyValues; public HuntsmanData Huntsman; public List<TimerField> TimerFields = new List<TimerField>(); } public static ConfigEntry<bool> EnableSizeRandomizer; public static ConfigEntry<bool> EnableSpeedRandomizer; public static ConfigEntry<float> MinScale; public static ConfigEntry<float> MaxScale; public static ConfigEntry<float> MinSpeedMultiplier; public static ConfigEntry<float> MaxSpeedMultiplier; public static ConfigEntry<bool> SpeedAnimations; public static ConfigEntry<bool> SpeedAttackTimers; public static ConfigEntry<float> MinAudioPitch; public static ConfigEntry<float> MaxAudioPitch; public static ConfigEntry<float> DamageSizeInfluence; public static ConfigEntry<float> MinimumDamageMultiplier; public static ConfigEntry<float> MaximumDamageMultiplier; private static readonly Dictionary<EnemyParent, EnemyData> Enemies = new Dictionary<EnemyParent, EnemyData>(); private void Awake() { EnableSizeRandomizer = ((BaseUnityPlugin)this).Config.Bind<bool>("Randomizers", "EnableSizeRandomizer", true, "Randomize enemy sizes."); EnableSpeedRandomizer = ((BaseUnityPlugin)this).Config.Bind<bool>("Randomizers", "EnableSpeedRandomizer", true, "Randomize enemy speed."); MinScale = ((BaseUnityPlugin)this).Config.Bind<float>("Size", "MinScale", 0.15f, "Smallest enemy size. 1.0 = normal size."); MaxScale = ((BaseUnityPlugin)this).Config.Bind<float>("Size", "MaxScale", 2f, "Largest enemy size. 1.0 = normal size."); MinSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Speed", "MinSpeedMultiplier", 1f, "Slowest enemy speed. 1.0 = normal speed."); MaxSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Speed", "MaxSpeedMultiplier", 5f, "Fastest enemy speed. 1.0 = normal speed."); SpeedAnimations = ((BaseUnityPlugin)this).Config.Bind<bool>("SpeedBehavior", "SpeedAnimations", true, "Make supported enemy animations use the random speed multiplier."); SpeedAttackTimers = ((BaseUnityPlugin)this).Config.Bind<bool>("SpeedBehavior", "SpeedAttackTimers", true, "Make supported enemy cooldown, delay, charge, recovery and attack timers faster."); MinAudioPitch = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "MinAudioPitch", 0.5f, "Lowest pitch allowed for large enemies."); MaxAudioPitch = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "MaxAudioPitch", 1.8f, "Highest pitch allowed for small enemies."); DamageSizeInfluence = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "DamageSizeInfluence", 0.2f, "How strongly size affects damage. 0.20 means 1.5x size = 1.10x damage."); MinimumDamageMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "MinimumDamageMultiplier", 0.8f, "Lowest damage multiplier caused by size."); MaximumDamageMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "MaximumDamageMultiplier", 1.2f, "Highest damage multiplier caused by size."); Harmony.CreateAndPatchAll(typeof(EnemySizeRandomizerPlugin), (string)null); Debug.Log((object)"[EnemySizeRandomizer] Loaded version 1.5.3"); } [HarmonyPostfix] [HarmonyPatch(typeof(EnemyParent), "SpawnRPC")] private static void OnEnemySpawn(EnemyParent __instance) { if (!((Object)(object)__instance == (Object)null)) { Debug.Log((object)"[EnemySizeRandomizer] SpawnRPC detected."); if (PhotonNetwork.IsMasterClient) { ((MonoBehaviour)__instance).StartCoroutine(SetupEnemyAfterSpawn(__instance)); } } } private static IEnumerator SetupEnemyAfterSpawn(EnemyParent enemy) { yield return null; yield return null; yield return null; if ((Object)(object)enemy == (Object)null) { yield break; } ScaleController controller = ((Component)enemy).GetComponentInChildren<ScaleController>(true); if ((Object)(object)controller == (Object)null) { Debug.LogWarning((object)"[EnemySizeRandomizer] Could not find ScalerCore ScaleController."); yield break; } float size = 1f; if (EnableSizeRandomizer.Value) { size = Random.Range(MinScale.Value, MaxScale.Value); } float speed = 1f; if (EnableSpeedRandomizer.Value) { speed = Random.Range(MinSpeedMultiplier.Value, MaxSpeedMultiplier.Value); } Animator[] animators = ((Component)enemy).GetComponentsInChildren<Animator>(true); AudioSource[] audioSources = ((Component)enemy).GetComponentsInChildren<AudioSource>(true); EnemyRigidbody enemyRigidbody = ((Component)enemy).GetComponentInChildren<EnemyRigidbody>(true); EnemyData data = new EnemyData { Enemy = enemy, Controller = controller, Size = size, Speed = speed, Animators = animators, AudioSources = audioSources, EnemyRigidbody = enemyRigidbody }; data.TimerFields = FindTimerFields(enemy); if ((Object)(object)enemyRigidbody != (Object)null) { data.OriginalPositionSpeedChase = enemyRigidbody.positionSpeedChase; data.OriginalPositionSpeedIdle = enemyRigidbody.positionSpeedIdle; data.OriginalRotationSpeedChase = enemyRigidbody.rotationSpeedChase; data.OriginalRotationSpeedIdle = enemyRigidbody.rotationSpeedIdle; data.OriginalGrabForce = enemyRigidbody.grabForceNeeded; data.HasOriginalRigidbodyValues = true; } EnemyHunter hunter = ((Component)enemy).GetComponentInChildren<EnemyHunter>(true); if ((Object)(object)hunter != (Object)null) { HuntsmanData huntsman = new HuntsmanData { Hunter = hunter }; if ((Object)(object)hunter.gunTipTransform != (Object)null) { huntsman.OriginalGunTipPosition = hunter.gunTipTransform.localPosition; huntsman.HasGunTip = true; } if ((Object)(object)hunter.gunAimTransform != (Object)null) { huntsman.OriginalGunAimPosition = hunter.gunAimTransform.localPosition; huntsman.HasGunAim = true; } data.Huntsman = huntsman; Debug.Log((object)"[EnemySizeRandomizer] Huntsman compatibility enabled."); } data.TimerFields = FindTimerFields(enemy); Enemies[enemy] = data; Debug.Log((object)("[EnemySizeRandomizer] Enemy randomized: " + $"Size {size:F2}x | " + $"Speed {speed:F2}x | " + $"Timers {data.TimerFields.Count}")); ScaleOptions options = ScaleOptions.Default; options.Factor = size; options.SpeedFactor = speed; options.PreserveMass = true; options.AllowedTargets = (ScaleTargets)2; options.SuppressVoicePitch = false; options.IgnoreBonkExpand = true; options.Duration = 0f; ScaleManager.Apply(((Component)controller).gameObject, options); Debug.Log((object)"[EnemySizeRandomizer] ScalerCore Apply() called."); yield return null; RestoreSpeedIndependence(data); RestoreGrabForce(data); ApplyHuntsmanTransformFix(data); ApplyAnimationSpeed(data); ApplyAudioPitch(data); } private void Update() { if (Enemies.Count == 0) { return; } List<EnemyParent> list = new List<EnemyParent>(); foreach (KeyValuePair<EnemyParent, EnemyData> enemy in Enemies) { EnemyParent key = enemy.Key; EnemyData value = enemy.Value; if ((Object)(object)key == (Object)null) { list.Add(key); continue; } RestoreSpeedIndependence(value); RestoreGrabForce(value); ApplyHuntsmanTransformFix(value); if (SpeedAnimations.Value) { ApplyAnimationSpeed(value); } ApplyAudioPitch(value); if (SpeedAttackTimers.Value) { AccelerateTimers(value); } } foreach (EnemyParent item in list) { Enemies.Remove(item); } } private static void RestoreSpeedIndependence(EnemyData data) { if (data != null && !((Object)(object)data.EnemyRigidbody == (Object)null) && data.HasOriginalRigidbodyValues && EnableSpeedRandomizer.Value) { data.EnemyRigidbody.positionSpeedChase = data.OriginalPositionSpeedChase * data.Speed; data.EnemyRigidbody.positionSpeedIdle = data.OriginalPositionSpeedIdle * data.Speed; data.EnemyRigidbody.rotationSpeedChase = data.OriginalRotationSpeedChase * data.Speed; data.EnemyRigidbody.rotationSpeedIdle = data.OriginalRotationSpeedIdle * data.Speed; } } private static void RestoreGrabForce(EnemyData data) { if (data != null && !((Object)(object)data.EnemyRigidbody == (Object)null) && data.HasOriginalRigidbodyValues) { data.EnemyRigidbody.grabForceNeeded = data.OriginalGrabForce; } } private static void ApplyHuntsmanTransformFix(EnemyData data) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) if (data == null || data.Huntsman == null) { return; } EnemyHunter hunter = data.Huntsman.Hunter; if (!((Object)(object)hunter == (Object)null)) { float size = data.Size; if (data.Huntsman.HasGunTip && (Object)(object)hunter.gunTipTransform != (Object)null) { hunter.gunTipTransform.localPosition = data.Huntsman.OriginalGunTipPosition * size; } if (data.Huntsman.HasGunAim && (Object)(object)hunter.gunAimTransform != (Object)null) { hunter.gunAimTransform.localPosition = data.Huntsman.OriginalGunAimPosition * size; } } } private static void ApplyAnimationSpeed(EnemyData data) { if (data == null || data.Animators == null) { return; } Animator[] animators = data.Animators; foreach (Animator val in animators) { if (!((Object)(object)val == (Object)null) && ((Behaviour)val).enabled) { val.speed = data.Speed; } } } private static void ApplyAudioPitch(EnemyData data) { if (data == null || data.AudioSources == null) { return; } float num = Mathf.Max(0.01f, data.Size); float num2 = Mathf.Pow(1f / num, 0.75f); num2 = Mathf.Clamp(num2, MinAudioPitch.Value, MaxAudioPitch.Value); AudioSource[] audioSources = data.AudioSources; foreach (AudioSource val in audioSources) { if (!((Object)(object)val == (Object)null)) { val.pitch = num2; } } } private static List<TimerField> FindTimerFields(EnemyParent enemy) { List<TimerField> list = new List<TimerField>(); MonoBehaviour[] componentsInChildren = ((Component)enemy).GetComponentsInChildren<MonoBehaviour>(true); MonoBehaviour[] array = componentsInChildren; foreach (MonoBehaviour val in array) { if ((Object)(object)val == (Object)null) { continue; } Type type = ((object)val).GetType(); FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo[] array2 = fields; foreach (FieldInfo fieldInfo in array2) { if (!(fieldInfo.FieldType != typeof(float))) { string name = fieldInfo.Name.ToLowerInvariant(); if (LooksLikeAttackTimer(name) && !LooksLikeProtectedTimer(name)) { list.Add(new TimerField { Owner = val, Field = fieldInfo }); } } } } return list; } private static bool LooksLikeAttackTimer(string name) { return name.Contains("cooldown") || name.Contains("delay") || name.Contains("wait") || name.Contains("charge") || name.Contains("attackinterval") || name.Contains("attackcooldown") || name.Contains("recovery") || name.Contains("reload") || name.Contains("casttime") || name.Contains("windup"); } private static bool LooksLikeProtectedTimer(string name) { return name.Contains("stun") || name.Contains("freeze") || name.Contains("frozen") || name.Contains("invincible") || name.Contains("invulnerability") || name.Contains("death") || name.Contains("dead") || name.Contains("disable") || name.Contains("respawn"); } private static void AccelerateTimers(EnemyData data) { if (data == null || data.TimerFields == null) { return; } float speed = data.Speed; if (Mathf.Approximately(speed, 1f)) { return; } float num = Time.deltaTime * (speed - 1f); foreach (TimerField timerField in data.TimerFields) { if (timerField.Owner == null || timerField.Field == null) { continue; } try { float num2 = (float)timerField.Field.GetValue(timerField.Owner); if (!(num2 <= 0f)) { num2 -= num; if (num2 < 0f) { num2 = 0f; } timerField.Field.SetValue(timerField.Owner, num2); } } catch { } } } [HarmonyPriority(0)] [HarmonyPrefix] [HarmonyPatch(typeof(HurtCollider), "PlayerHurt")] private static void SoftenEnemyDamage(HurtCollider __instance) { if (!EnableSizeRandomizer.Value || (Object)(object)__instance == (Object)null) { return; } EnemyParent componentInParent = ((Component)__instance).GetComponentInParent<EnemyParent>(); if (!((Object)(object)componentInParent == (Object)null) && Enemies.TryGetValue(componentInParent, out var value)) { float size = value.Size; if (!(size <= 0.0001f)) { float num = 1f + (size - 1f) * DamageSizeInfluence.Value; num = Mathf.Clamp(num, MinimumDamageMultiplier.Value, MaximumDamageMultiplier.Value); float num2 = num / size; __instance.playerDamage = Mathf.RoundToInt((float)__instance.playerDamage * num2); __instance.playerTumbleImpactHurtDamage = Mathf.RoundToInt((float)__instance.playerTumbleImpactHurtDamage * num2); } } } } }