using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using CzajnikXD.TF2MinigunMod.Behaviours; using CzajnikXD.TF2MinigunMod.Patches; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("TF2Minigun")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.4.0")] [assembly: AssemblyInformationalVersion("1.0.4")] [assembly: AssemblyProduct("TF2Minigun")] [assembly: AssemblyTitle("TF2Minigun")] [assembly: AssemblyVersion("1.0.4.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace CzajnikXD.TF2MinigunMod { [BepInPlugin("com.czajnikxd.repo.tf2minigunmod", "TF2 Minigun Mod", "1.0.4")] public class TF2MinigunPlugin : BaseUnityPlugin { private readonly Harmony harmony = new Harmony("com.czajnikxd.repo.tf2minigunmod"); private void Awake() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"TF2 Minigun Mod is loading and patching!"); harmony.PatchAll(typeof(ItemGunPatches)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"TF2 Minigun Mod patches applied."); } } } namespace CzajnikXD.TF2MinigunMod.Behaviours { [RequireComponent(typeof(PhotonView))] public class MinigunContinuousFireLogic : MonoBehaviour { public enum MinigunState { Idle, WindingUp, Spinning, Shooting, ShootingEmpty, WindingDown } private ItemGun itemGun; private ItemToggle itemToggle; private ItemBattery itemBattery; private PhysGrabObject physGrabObject; private float localShootCooldownTimer; public MinigunState currentState; public MinigunState previousStateForLog; public float windUpDuration = 0.87f; public float windDownDuration = 0.87f; private float stateTimer; public KeyCode fireKey = (KeyCode)101; public AudioClip windUpAudioClip; public AudioClip windDownAudioClip; public AudioClip spinLoopAudioClip; public AudioClip shootLoopAudioClip; public AudioClip emptyShootAudioClip; [Range(0f, 1f)] public float windUpVolume = 0.1f; [Range(0f, 1f)] public float windDownVolume = 0.1f; [Range(0f, 1f)] public float spinLoopVolume = 0.05f; [Range(0f, 1f)] public float shootLoopVolume = 0.1f; [Range(0f, 1f)] public float emptyShootVolume = 0.1f; private AudioSource windUpAudioSource; private AudioSource windDownAudioSource; private AudioSource spinAudioSourceComponent; private AudioSource shootLoopAudioSource; private AudioSource emptyShootAudioSource; private bool canShootAfterWindUp; private static MethodInfo _startTriggerAnimMethod; private void Awake() { itemGun = ((Component)this).GetComponent(); itemToggle = ((Component)this).GetComponent(); itemBattery = ((Component)this).GetComponent(); physGrabObject = ((Component)this).GetComponent(); if ((Object)(object)itemGun == (Object)null) { Debug.LogError((object)"[MinigunLogic] ItemGun component not found!"); ((Behaviour)this).enabled = false; return; } if ((Object)(object)itemBattery == (Object)null) { Debug.LogError((object)"[MinigunLogic] ItemBattery component not found!"); ((Behaviour)this).enabled = false; return; } if ((Object)(object)physGrabObject == (Object)null) { Debug.LogError((object)"[MinigunLogic] PhysGrabObject component not found!"); ((Behaviour)this).enabled = false; return; } itemGun.batteryDrainFullBar = false; if (itemGun.batteryDrain <= 0f || itemGun.batteryDrain > 5f) { itemGun.batteryDrain = 1f; } int batteryBars = Mathf.Clamp(Mathf.RoundToInt(100f / Mathf.Max(itemGun.batteryDrain, 0.01f)), 6, 20); itemBattery.batteryBars = batteryBars; windUpAudioSource = SetupAudioSource(windUpAudioClip, loop: false, windUpVolume, "WindUp"); windDownAudioSource = SetupAudioSource(windDownAudioClip, loop: false, windDownVolume, "WindDown"); spinAudioSourceComponent = SetupAudioSource(spinLoopAudioClip, loop: true, spinLoopVolume, "SpinLoop"); shootLoopAudioSource = SetupAudioSource(shootLoopAudioClip, loop: true, shootLoopVolume, "ShootLoop"); emptyShootAudioSource = SetupAudioSource(emptyShootAudioClip, loop: false, emptyShootVolume, "EmptyShoot"); previousStateForLog = currentState; if (_startTriggerAnimMethod == null) { _startTriggerAnimMethod = typeof(ItemGun).GetMethod("StartTriggerAnimation", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } } private AudioSource SetupAudioSource(AudioClip clip, bool loop, float volume = 1f, string sourceNameForDebug = "Unnamed") { if ((Object)(object)clip == (Object)null) { Debug.LogWarning((object)("[MinigunLogic] AudioClip for '" + sourceNameForDebug + "' is not assigned. This sound will not play.")); return null; } AudioSource obj = ((Component)this).gameObject.AddComponent(); obj.clip = clip; obj.loop = loop; obj.playOnAwake = false; obj.volume = volume; return obj; } private void Update() { //IL_0076: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)itemGun == (Object)null || (Object)(object)physGrabObject == (Object)null || !physGrabObject.grabbed || !physGrabObject.grabbedLocal) { if (currentState != 0 && currentState != MinigunState.WindingDown) { TransitionToState(MinigunState.WindingDown); } UpdateStateMachine(isFireKeyPressed: false); return; } if (localShootCooldownTimer > 0f) { localShootCooldownTimer -= Time.deltaTime; } bool key = Input.GetKey(fireKey); UpdateStateMachine(key); } public void UpdateStateMachine(bool isFireKeyPressed) { stateTimer += Time.deltaTime; MinigunState minigunState = currentState; switch (currentState) { case MinigunState.Idle: if (isFireKeyPressed) { minigunState = MinigunState.WindingUp; } break; case MinigunState.WindingUp: canShootAfterWindUp = false; if (!isFireKeyPressed) { minigunState = MinigunState.WindingDown; } else if (stateTimer >= windUpDuration) { minigunState = MinigunState.Spinning; canShootAfterWindUp = true; } break; case MinigunState.Spinning: minigunState = (isFireKeyPressed ? ((!(itemBattery.batteryLife <= 0f)) ? MinigunState.Shooting : MinigunState.ShootingEmpty) : MinigunState.WindingDown); break; case MinigunState.Shooting: if (!isFireKeyPressed) { minigunState = MinigunState.WindingDown; } else if (itemBattery.batteryLife <= 0f) { minigunState = MinigunState.ShootingEmpty; } else if (canShootAfterWindUp && localShootCooldownTimer <= 0f) { itemGun.Shoot(); localShootCooldownTimer = itemGun.shootCooldown; } break; case MinigunState.ShootingEmpty: if (!isFireKeyPressed) { minigunState = MinigunState.WindingDown; } else if (itemBattery.batteryLife > 0f) { minigunState = MinigunState.Shooting; } else if (localShootCooldownTimer <= 0f) { AudioSource obj = emptyShootAudioSource; if (obj != null) { obj.PlayOneShot(emptyShootAudioSource.clip, emptyShootAudioSource.volume); } _startTriggerAnimMethod?.Invoke(itemGun, null); localShootCooldownTimer = itemGun.shootCooldown; } break; case MinigunState.WindingDown: canShootAfterWindUp = false; if (stateTimer >= windDownDuration) { minigunState = MinigunState.Idle; } else if (isFireKeyPressed) { minigunState = MinigunState.WindingUp; } break; } if (minigunState != currentState) { TransitionToState(minigunState); } } private void TransitionToState(MinigunState newState) { if (currentState != newState || newState == MinigunState.Idle || newState == MinigunState.WindingUp) { previousStateForLog = currentState; OnStateExit(currentState, newState); currentState = newState; stateTimer = 0f; OnStateEnter(newState); } } private void OnStateEnter(MinigunState state) { switch (state) { case MinigunState.WindingUp: { AudioSource obj3 = windUpAudioSource; if (obj3 != null) { obj3.Play(); } StartSpinSound(); StopShootLoopSound(); break; } case MinigunState.Spinning: StartSpinSound(); StopShootLoopSound(); break; case MinigunState.Shooting: StartSpinSound(); StartShootLoopSound(); break; case MinigunState.ShootingEmpty: StartSpinSound(); StopShootLoopSound(); break; case MinigunState.WindingDown: { AudioSource obj = windDownAudioSource; if (obj != null) { obj.Play(); } AudioSource obj2 = windUpAudioSource; if (obj2 != null) { obj2.Stop(); } StopSpinSound(); break; } case MinigunState.Idle: StopAllMinigunSounds(); canShootAfterWindUp = false; break; } } private void OnStateExit(MinigunState oldState, MinigunState newState) { if (oldState == MinigunState.WindingUp && newState != MinigunState.Spinning && newState != MinigunState.WindingDown) { AudioSource obj = windUpAudioSource; if (obj != null) { obj.Stop(); } } if (oldState == MinigunState.WindingDown && newState != 0 && newState != MinigunState.WindingUp) { AudioSource obj2 = windDownAudioSource; if (obj2 != null) { obj2.Stop(); } } if (oldState == MinigunState.Shooting && newState != MinigunState.Shooting) { StopShootLoopSound(); } if ((oldState == MinigunState.WindingUp || oldState == MinigunState.Spinning || oldState == MinigunState.Shooting || oldState == MinigunState.ShootingEmpty || oldState == MinigunState.WindingDown) && newState == MinigunState.Idle) { StopSpinSound(); StopShootLoopSound(); } } private void StartSpinSound() { if ((Object)(object)spinAudioSourceComponent != (Object)null && !spinAudioSourceComponent.isPlaying) { spinAudioSourceComponent.Play(); } } private void StopSpinSound() { if ((Object)(object)spinAudioSourceComponent != (Object)null && spinAudioSourceComponent.isPlaying) { spinAudioSourceComponent.Stop(); } } private void StartShootLoopSound() { if ((Object)(object)shootLoopAudioSource != (Object)null && !shootLoopAudioSource.isPlaying) { shootLoopAudioSource.Play(); } } private void StopShootLoopSound() { if ((Object)(object)shootLoopAudioSource != (Object)null && shootLoopAudioSource.isPlaying) { shootLoopAudioSource.Stop(); } } private void StopAllMinigunSounds(bool includeSpinAndShootLoops = true) { AudioSource obj = windUpAudioSource; if (obj != null) { obj.Stop(); } AudioSource obj2 = windDownAudioSource; if (obj2 != null) { obj2.Stop(); } AudioSource obj3 = emptyShootAudioSource; if (obj3 != null) { obj3.Stop(); } if (includeSpinAndShootLoops) { StopSpinSound(); StopShootLoopSound(); } } private void OnDestroy() { StopAllMinigunSounds(); if ((Object)(object)spinAudioSourceComponent != (Object)null) { Object.Destroy((Object)(object)spinAudioSourceComponent); } if ((Object)(object)windUpAudioSource != (Object)null) { Object.Destroy((Object)(object)windUpAudioSource); } if ((Object)(object)windDownAudioSource != (Object)null) { Object.Destroy((Object)(object)windDownAudioSource); } if ((Object)(object)shootLoopAudioSource != (Object)null) { Object.Destroy((Object)(object)shootLoopAudioSource); } if ((Object)(object)emptyShootAudioSource != (Object)null) { Object.Destroy((Object)(object)emptyShootAudioSource); } } } } namespace CzajnikXD.TF2MinigunMod.Patches { public static class ItemGunPatches { [HarmonyPatch(typeof(ItemGun), "UpdateMaster")] public static class ItemGun_UpdateMaster_Patch { private static bool Prefix(ItemGun __instance, ref bool ___prevToggleState, ItemToggle ___itemToggle) { MinigunContinuousFireLogic component = ((Component)__instance).GetComponent(); if ((Object)(object)component != (Object)null && ((Behaviour)component).enabled) { if ((Object)(object)___itemToggle != (Object)null) { ___prevToggleState = ___itemToggle.toggleState; } return true; } return true; } } [HarmonyPatch(typeof(ItemGun), "Misfire")] public static class ItemGun_Misfire_Patch { private static bool Prefix(ItemGun __instance) { MinigunContinuousFireLogic component = ((Component)__instance).GetComponent(); if ((Object)(object)component != (Object)null && ((Behaviour)component).enabled) { return false; } return true; } } [HarmonyPatch(typeof(ItemGun), "ShootRPC")] public static class ItemGun_ShootRPC_Patch { private static bool Prefix(ItemGun __instance) { return true; } } } }