The BepInEx console will not appear when launching like it does for other games on Thunderstore (you can turn it back on in your BepInEx.cfg file). If your PEAK crashes on startup, add -dx12 to your launch parameters.
Decompiled source of Useable Dynamite v1.0.1
tony4twentys-Useable Dynamite.dll
Decompiled a month agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using ExitGames.Client.Photon; using HarmonyLib; using Photon.Pun; using Photon.Realtime; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("Useable Dynamite")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Useable Dynamite")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("c6b6a11e-1b4e-4eec-8d52-1556e2cd79d2")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] [BepInPlugin("tony4twentys.DynamiteFuseCancel", "Dynamite Fuse Cancel", "2.17.1")] public class DynamiteFuseCancel : BaseUnityPlugin, IOnEventCallback { [CompilerGenerated] private sealed class <ApprovalPoller>d__32 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public DynamiteFuseCancel <>4__this; private WaitForSeconds <wait>5__1; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ApprovalPoller>d__32(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <wait>5__1 = null; <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <wait>5__1 = new WaitForSeconds(1f); break; case 1: <>1__state = -1; break; } <>4__this.EvaluateHostApproval(); <>2__current = <wait>5__1; <>1__state = 1; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <SuppressLoop>d__36 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public DynamiteFuseCancel <>4__this; private float <last>5__1; private WaitForSeconds <wait>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SuppressLoop>d__36(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <wait>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <last>5__1 = Mathf.Max(0.02f, <>4__this._checkInterval.Value); <wait>5__2 = new WaitForSeconds(<last>5__1); break; case 1: <>1__state = -1; break; } if (<>4__this._running) { if (!Mathf.Approximately(<last>5__1, <>4__this._checkInterval.Value)) { <last>5__1 = Mathf.Max(0.02f, <>4__this._checkInterval.Value); <wait>5__2 = new WaitForSeconds(<last>5__1); } <>4__this.DoScanStep(); <>2__current = <wait>5__2; <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private ConfigEntry<float> _checkInterval; private ConfigEntry<float> _safeFuelBuffer; private ConfigEntry<bool> _killVfxAudio; private ConfigEntry<bool> _allowPocket; private ConfigEntry<float> _explosionMaxTTL; private const string HOST_PROP = "DFC_HOST"; private bool _running; private const byte EVT_SUPPRESS = 177; private readonly Dictionary<int, float> _origRadius = new Dictionary<int, float>(); private readonly HashSet<int> _smokeCleared = new HashSet<int>(); private readonly Dictionary<int, int> _smokeRetry = new Dictionary<int, int>(); private readonly Dictionary<int, bool> _localSupp = new Dictionary<int, bool>(); private readonly Dictionary<int, float> _lastAnnounce = new Dictionary<int, float>(); private readonly Dictionary<int, bool> _pendingSuppress = new Dictionary<int, bool>(); private readonly Dictionary<int, int> _pendingRetries = new Dictionary<int, int>(); private readonly HashSet<int> _netSuppressed = new HashSet<int>(); private readonly HashSet<int> _manuallyLit = new HashSet<int>(); private readonly HashSet<int> _hookedItems = new HashSet<int>(); private readonly Dictionary<int, byte> _armedSlotById = new Dictionary<int, byte>(); private readonly Dictionary<int, ushort> _armedItemIdByView = new Dictionary<int, ushort>(); private readonly Dictionary<int, float> _manualGraceUntil = new Dictionary<int, float>(); private readonly Dictionary<int, float> _stashedGraceUntil = new Dictionary<int, float>(); private Coroutine _loop; public static float ExplosionMaxTTL { get; private set; } = 5f; private void Awake() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) try { new Harmony("tony4twentys.DFC.VFXTTL").PatchAll(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[DFC] Harmony patch failed: " + ex.Message)); } _checkInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "CheckInterval", 0.1f, "Scan interval in seconds (0.05–0.25)."); _safeFuelBuffer = ((BaseUnityPlugin)this).Config.Bind<float>("General", "SafeFuelBuffer", 5f, "Minimum fuel while suppressed."); _killVfxAudio = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "KillVfxAudio", true, "Remove smoke VFX & stop fuse audio while suppressed."); _allowPocket = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AllowPocket", true, "Force item.UIData.canPocket = true."); _explosionMaxTTL = ((BaseUnityPlugin)this).Config.Bind<float>("VFX", "ExplosionMaxTTL", 5f, "Max seconds VFX_DynamiteExplosion stays alive (RemoveAfterSeconds.seconds)."); ExplosionMaxTTL = Mathf.Max(0.25f, _explosionMaxTTL.Value); if (_checkInterval.Value < 0.02f) { _checkInterval.Value = 0.02f; } if (_safeFuelBuffer.Value < 0f) { _safeFuelBuffer.Value = 0f; } SceneManager.activeSceneChanged += OnSceneChanged; PhotonNetwork.AddCallbackTarget((object)this); } private void Start() { ((MonoBehaviour)this).StartCoroutine(ApprovalPoller()); } private void OnDestroy() { SceneManager.activeSceneChanged -= OnSceneChanged; PhotonNetwork.RemoveCallbackTarget((object)this); StopLoop(); ClearStateCaches(); } private void OnSceneChanged(Scene _, Scene __) { ClearStateCaches(); } private void ClearStateCaches() { _origRadius.Clear(); _smokeCleared.Clear(); _smokeRetry.Clear(); _localSupp.Clear(); _lastAnnounce.Clear(); _pendingSuppress.Clear(); _pendingRetries.Clear(); _netSuppressed.Clear(); _manuallyLit.Clear(); _hookedItems.Clear(); _armedSlotById.Clear(); _armedItemIdByView.Clear(); _manualGraceUntil.Clear(); _stashedGraceUntil.Clear(); } [IteratorStateMachine(typeof(<ApprovalPoller>d__32))] private IEnumerator ApprovalPoller() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ApprovalPoller>d__32(0) { <>4__this = this }; } private void EvaluateHostApproval() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_004b: Expected O, but got Unknown if (!PhotonNetwork.InRoom) { StopLoop(); return; } if (PhotonNetwork.IsMasterClient) { Player localPlayer = PhotonNetwork.LocalPlayer; Hashtable val = new Hashtable(); ((Dictionary<object, object>)val).Add((object)"DFC_HOST", (object)true); localPlayer.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); StartLoop(); return; } Player masterClient = PhotonNetwork.MasterClient; bool flag = default(bool); int num; if (masterClient != null && masterClient.CustomProperties != null && ((Dictionary<object, object>)(object)masterClient.CustomProperties).TryGetValue((object)"DFC_HOST", out object value)) { if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } } else { num = 0; } if (((uint)num & (flag ? 1u : 0u)) != 0) { StartLoop(); } else { StopLoop(); } } private void StartLoop() { if (!_running) { _running = true; DoScanStep(); _loop = ((MonoBehaviour)this).StartCoroutine(SuppressLoop()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[DFC] Loop started (host-approved)."); } } private void StopLoop() { if (_running) { _running = false; if (_loop != null) { ((MonoBehaviour)this).StopCoroutine(_loop); } _loop = null; ((BaseUnityPlugin)this).Logger.LogInfo((object)"[DFC] Loop stopped."); } } [IteratorStateMachine(typeof(<SuppressLoop>d__36))] private IEnumerator SuppressLoop() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SuppressLoop>d__36(0) { <>4__this = this }; } private void DoScanStep() { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Invalid comparison between Unknown and I4 Dynamite[] array = Object.FindObjectsByType<Dynamite>((FindObjectsSortMode)0); Dynamite[] array2 = array; foreach (Dynamite val in array2) { if (!Object.op_Implicit((Object)(object)val)) { continue; } Item component = ((Component)val).GetComponent<Item>(); if (!Object.op_Implicit((Object)(object)component)) { continue; } PhotonView component2 = ((Component)val).GetComponent<PhotonView>(); int key = GetKey(val); WireHooks(component, val, key); bool flag = false; Character localCharacter = Character.localCharacter; if (Object.op_Implicit((Object)(object)localCharacter)) { CharacterData component3 = ((Component)localCharacter).GetComponent<CharacterData>(); if (Object.op_Implicit((Object)(object)component3) && (Object)(object)component3.currentItem == (Object)(object)component) { flag = true; } } bool flag2 = (int)component.itemState == 2; if (flag2 && _manuallyLit.Contains(key)) { ExtinguishAndReset(component, val); _stashedGraceUntil[key] = Time.time + 1f; _manuallyLit.Remove(key); _armedSlotById.Remove(key); _netSuppressed.Add(key); } float value; bool flag3 = _manualGraceUntil.TryGetValue(key, out value) && Time.time < value; bool flag4 = (flag || flag2) && !_manuallyLit.Contains(key) && !flag3; if (flag4 || _netSuppressed.Contains(key)) { EnforceSuppressedState(val, component, key); } else { RestoreState(val, key); } bool value2; bool flag5 = _localSupp.TryGetValue(key, out value2) && value2; if (flag4 != flag5) { _localSupp[key] = flag4; BroadcastSuppress(component2, key, flag4, force: true); if (flag4) { _netSuppressed.Add(key); } else { _netSuppressed.Remove(key); } } else if (flag4) { BroadcastSuppress(component2, key, suppress: true, force: false); _netSuppressed.Add(key); } if (!flag && !flag2 && _manuallyLit.Contains(key)) { _manuallyLit.Remove(key); } if (!flag2) { _stashedGraceUntil.Remove(key); } } CleanupExplodedOrStashed(); if (_pendingSuppress.Count <= 0) { return; } List<int> list = new List<int>(_pendingSuppress.Keys); foreach (int item in list) { PhotonView val2 = PhotonView.Find(item); _pendingRetries.TryGetValue(item, out var value3); if ((Object)(object)val2 != (Object)null) { Dynamite component4 = ((Component)val2).GetComponent<Dynamite>(); Item component5 = ((Component)val2).GetComponent<Item>(); if (Object.op_Implicit((Object)(object)component4) && Object.op_Implicit((Object)(object)component5)) { if (_pendingSuppress[item]) { _netSuppressed.Add(item); EnforceSuppressedState(component4, component5, item); } else { _netSuppressed.Remove(item); RestoreState(component4, item); } _pendingSuppress.Remove(item); _pendingRetries.Remove(item); continue; } } value3++; if (value3 > 20) { _pendingSuppress.Remove(item); _pendingRetries.Remove(item); } else { _pendingRetries[item] = value3; } } } private void WireHooks(Item item, Dynamite dyn, int id) { if (_hookedItems.Contains(id)) { return; } _hookedItems.Add(id); Item obj = item; obj.OnPrimaryFinishedCast = (Action)Delegate.Combine(obj.OnPrimaryFinishedCast, (Action)delegate { TryManualLight(dyn, item, id); }); Item obj2 = item; obj2.OnStateChange = (Action<ItemState>)Delegate.Combine(obj2.OnStateChange, (Action<ItemState>)delegate(ItemState state) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 if ((int)state == 2 && _manuallyLit.Contains(id)) { ExtinguishAndReset(item, dyn); _stashedGraceUntil[id] = Time.time + 1f; _manuallyLit.Remove(id); _armedSlotById.Remove(id); _netSuppressed.Add(id); _localSupp[id] = true; } }); } private void TryManualLight(Dynamite dyn, Item item, int id) { Character localCharacter = Character.localCharacter; if (!Object.op_Implicit((Object)(object)localCharacter)) { return; } CharacterData component = ((Component)localCharacter).GetComponent<CharacterData>(); if (!Object.op_Implicit((Object)(object)component) || (Object)(object)component.currentItem != (Object)(object)item) { return; } CharacterItems items = localCharacter.refs.items; if (Object.op_Implicit((Object)(object)items)) { if (items.currentSelectedSlot.IsSome) { _armedSlotById[id] = items.currentSelectedSlot.Value; } else if (items.lastSelectedSlot.IsSome) { _armedSlotById[id] = items.lastSelectedSlot.Value; } } _armedItemIdByView[id] = item.itemID; _manuallyLit.Add(id); _manualGraceUntil[id] = Time.time + 0.25f; _netSuppressed.Remove(id); BroadcastSuppress(((Component)dyn).GetComponent<PhotonView>(), id, suppress: false, force: true); dyn.LightFlare(); } private void EnforceSuppressedState(Dynamite dyn, Item item, int id) { if (!_origRadius.ContainsKey(id)) { _origRadius[id] = dyn.lightFuseRadius; } if (dyn.lightFuseRadius != 0f) { dyn.lightFuseRadius = 0f; } BoolItemData data = item.GetData<BoolItemData>((DataEntryKey)3); if (data != null && data.Value) { data.Value = false; } FloatItemData data2 = item.GetData<FloatItemData>((DataEntryKey)10); if (data2 != null && data2.Value < _safeFuelBuffer.Value) { data2.Value = _safeFuelBuffer.Value; } if (Object.op_Implicit((Object)(object)dyn.sparks) && ((Component)dyn.sparks).gameObject.activeSelf) { ((Component)dyn.sparks).gameObject.SetActive(false); } KillSmokeAndAudioNear(dyn, id); if (_allowPocket.Value && item.UIData != null) { item.UIData.canPocket = true; } } private void RestoreState(Dynamite dyn, int id) { if (_origRadius.TryGetValue(id, out var value)) { dyn.lightFuseRadius = value; _origRadius.Remove(id); } _smokeCleared.Remove(id); _smokeRetry.Remove(id); } private void ExtinguishAndReset(Item item, Dynamite dyn) { BoolItemData data = item.GetData<BoolItemData>((DataEntryKey)3); if (data != null) { data.Value = false; } FloatItemData data2 = item.GetData<FloatItemData>((DataEntryKey)10); if (data2 != null && data2.Value < _safeFuelBuffer.Value) { data2.Value = _safeFuelBuffer.Value; } if (Object.op_Implicit((Object)(object)dyn.sparks)) { ((Component)dyn.sparks).gameObject.SetActive(false); } AudioSource[] componentsInChildren = ((Component)dyn).GetComponentsInChildren<AudioSource>(); foreach (AudioSource val in componentsInChildren) { val.Stop(); } } private void CleanupExplodedOrStashed() { if (_armedSlotById.Count == 0 && _stashedGraceUntil.Count == 0) { return; } Character localCharacter = Character.localCharacter; if (!Object.op_Implicit((Object)(object)localCharacter) || !localCharacter.IsLocal) { return; } List<int> list = new List<int>(_armedSlotById.Keys); foreach (int item in list) { PhotonView val = PhotonView.Find(item); bool flag = (Object)(object)val == (Object)null; bool flag2 = false; if (!flag) { Dynamite component = ((Component)val).GetComponent<Dynamite>(); if (!Object.op_Implicit((Object)(object)component)) { flag = true; } else { flag2 = !((Component)component).gameObject.activeInHierarchy; } } if (!(flag || flag2)) { continue; } if (_stashedGraceUntil.TryGetValue(item, out var value) && Time.time < value) { _stashedGraceUntil.Remove(item); _armedSlotById.Remove(item); _armedItemIdByView.Remove(item); _manuallyLit.Remove(item); _netSuppressed.Add(item); continue; } bool flag3 = false; if (_armedItemIdByView.TryGetValue(item, out var value2)) { Player player = localCharacter.player; if ((Object)(object)player != (Object)null) { flag3 = player.HasInAnySlot(value2); } } _armedSlotById.Remove(item); _armedItemIdByView.Remove(item); _manuallyLit.Remove(item); if (flag3) { _netSuppressed.Add(item); } else { _netSuppressed.Remove(item); } } } public void OnEvent(EventData photonEvent) { if (photonEvent.Code != 177 || !(photonEvent.CustomData is object[] array) || array.Length < 2) { return; } int num = (int)array[0]; bool flag = (bool)array[1]; PhotonView val = PhotonView.Find(num); if ((Object)(object)val == (Object)null) { _pendingSuppress[num] = flag; _pendingRetries[num] = 0; return; } Dynamite component = ((Component)val).GetComponent<Dynamite>(); Item component2 = ((Component)val).GetComponent<Item>(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component2)) { if (flag) { _netSuppressed.Add(num); _manuallyLit.Remove(num); _manualGraceUntil.Remove(num); EnforceSuppressedState(component, component2, num); } else { _netSuppressed.Remove(num); RestoreState(component, num); } } } private void BroadcastSuppress(PhotonView pv, int id, bool suppress, bool force) { //IL_005a: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown if (!((Object)(object)pv == (Object)null) && (force || !_lastAnnounce.TryGetValue(id, out var value) || !(Time.time - value < 1f))) { PhotonNetwork.RaiseEvent((byte)177, (object)new object[2] { id, suppress }, new RaiseEventOptions { Receivers = (ReceiverGroup)0 }, SendOptions.SendReliable); _lastAnnounce[id] = Time.time; } } private int GetKey(Dynamite dyn) { PhotonView component = ((Component)dyn).GetComponent<PhotonView>(); return ((Object)(object)component != (Object)null) ? component.ViewID : ((Object)dyn).GetInstanceID(); } private void KillSmokeAndAudioNear(Dynamite dyn, int id) { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) if (!_killVfxAudio.Value || (Object)(object)dyn == (Object)null) { return; } _smokeRetry.TryGetValue(id, out var value); if (value >= 20 && _smokeCleared.Contains(id)) { return; } string value2 = (Object.op_Implicit((Object)(object)dyn.smokeVFXPrefab) ? ((Object)dyn.smokeVFXPrefab).name.ToLowerInvariant() : string.Empty); bool flag = false; TrackNetworkedObject[] array = Object.FindObjectsByType<TrackNetworkedObject>((FindObjectsSortMode)0); foreach (TrackNetworkedObject val in array) { if (!Object.op_Implicit((Object)(object)val) || Vector3.Distance(((Component)val).transform.position, ((Component)dyn).transform.position) > 3f) { continue; } string text = ((Object)val).name.ToLowerInvariant(); bool num; if (string.IsNullOrEmpty(value2)) { if (!text.Contains("smoke")) { num = text.Contains("flare"); goto IL_012e; } } else if (!text.Contains(value2) && !text.Contains("smoke")) { num = text.Contains("flare"); goto IL_012e; } goto IL_013d; IL_013d: AudioSource[] componentsInChildren = ((Component)val).GetComponentsInChildren<AudioSource>(); foreach (AudioSource val2 in componentsInChildren) { val2.Stop(); } ((Component)val).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)val).gameObject); flag = true; continue; IL_012e: if (!num) { continue; } goto IL_013d; } AudioSource[] componentsInChildren2 = ((Component)dyn).GetComponentsInChildren<AudioSource>(); foreach (AudioSource val3 in componentsInChildren2) { val3.Stop(); } if (flag) { _smokeCleared.Add(id); } _smokeRetry[id] = value + 1; } } namespace DFC; [HarmonyPatch] internal static class DFC_VFX_TTL { [HarmonyPrefix] [HarmonyPatch(typeof(RemoveAfterSeconds), "Start")] private static void Pre_RemoveAfterSeconds(RemoveAfterSeconds __instance) { try { GameObject val = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).gameObject : null); if (!Object.op_Implicit((Object)(object)val)) { return; } string name = ((Object)val).name; if (!string.IsNullOrEmpty(name) && name.IndexOf("VFX_DynamiteExplosion", StringComparison.OrdinalIgnoreCase) >= 0) { float explosionMaxTTL = DynamiteFuseCancel.ExplosionMaxTTL; if (__instance.seconds > explosionMaxTTL) { __instance.seconds = explosionMaxTTL; } } } catch { } } }