Decompiled source of RandomDynamite v1.7.0

plugins/RandomDynamite.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Photon.Pun;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("RandomDynamite")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.7.0.0")]
[assembly: AssemblyInformationalVersion("1.7.0")]
[assembly: AssemblyProduct("RandomDynamite")]
[assembly: AssemblyTitle("RandomDynamite")]
[assembly: AssemblyVersion("1.7.0.0")]
namespace RandomDynamite;

public enum ExplosionDetail
{
	Minimal,
	Particles,
	Full
}
[BepInPlugin("liam.RandomDynamite", "Random Dynamite", "1.7.0")]
public class Plugin : BaseUnityPlugin
{
	private struct PendingSpawn
	{
		public float Time;

		public Vector3 Position;
	}

	[HarmonyPatch(typeof(Dynamite), "EnableFlareVisuals")]
	internal static class DynamiteFlareVisualsPatch
	{
		private static bool Prefix(Dynamite __instance)
		{
			Plugin instance = Instance;
			if ((Object)(object)instance == (Object)null || !instance.SuppressSmoke)
			{
				return true;
			}
			return !instance.IsModDynamite(__instance);
		}
	}

	[HarmonyPatch(typeof(Dynamite), "Update")]
	internal static class DynamiteUpdatePatch
	{
		private static void Postfix(Dynamite __instance)
		{
			Plugin instance = Instance;
			if (!((Object)(object)instance == (Object)null) && instance.SuppressSparks && instance.IsModDynamite(__instance))
			{
				if ((Object)(object)__instance.sparks != (Object)null)
				{
					((Component)__instance.sparks).gameObject.SetActive(false);
				}
				if ((Object)(object)__instance.sparksPhotosensitive != (Object)null)
				{
					((Component)__instance.sparksPhotosensitive).gameObject.SetActive(false);
				}
			}
		}
	}

	public const string Guid = "liam.RandomDynamite";

	public const string Name = "Random Dynamite";

	public const string Version = "1.7.0";

	private const string FallbackDynamitePrefab = "Dynamite";

	internal static ManualLogSource Log;

	public static Plugin Instance;

	private ConfigEntry<bool> _enabledOnStart;

	private ConfigEntry<KeyCode> _toggleKey;

	private ConfigEntry<KeyCode> _manualBurstKey;

	private ConfigEntry<float> _intervalMin;

	private ConfigEntry<float> _intervalMax;

	private ConfigEntry<int> _countMin;

	private ConfigEntry<int> _countMax;

	private ConfigEntry<float> _heightMin;

	private ConfigEntry<float> _heightMax;

	private ConfigEntry<float> _spreadRadius;

	private ConfigEntry<float> _burstSpreadTime;

	private ConfigEntry<bool> _spawnOnEnable;

	private ConfigEntry<bool> _includeLocalPlayer;

	private ConfigEntry<bool> _onlyAlive;

	private ConfigEntry<bool> _lightFuses;

	private ConfigEntry<bool> _verbose;

	private ConfigEntry<bool> _suppressSmoke;

	private ConfigEntry<bool> _suppressSparks;

	private ConfigEntry<ExplosionDetail> _explosionDetail;

	private ConfigEntry<bool> _randomiseFuse;

	private ConfigEntry<float> _fuseJitterMin;

	private ConfigEntry<float> _fuseJitterMax;

	private ConfigEntry<int> _maxLiveDynamite;

	private ConfigEntry<bool> _messagesEnabled;

	private ConfigEntry<bool> _useGameNotifications;

	private ConfigEntry<float> _messageDuration;

	private ConfigEntry<bool> _persistentIndicator;

	private bool _active;

	private float _nextSpawnTime = float.MaxValue;

	private bool _legacyInputAvailable = true;

	private string _dynamitePrefabName;

	private bool _loggedInputDiagnostics;

	private bool _wasInRoom;

	private readonly HashSet<Dynamite> _modDynamite = new HashSet<Dynamite>();

	private readonly List<Dynamite> _staleDynamite = new List<Dynamite>();

	private float _nextCleanupTime;

	private bool _loggedExplosionPrefab;

	private readonly Queue<PendingSpawn> _pendingSpawns = new Queue<PendingSpawn>();

	private static readonly List<Character> Targets = new List<Character>();

	private string _toastText;

	private float _toastUntil;

	private GUIStyle _toastStyle;

	private GUIStyle _indicatorStyle;

	private Texture2D _toastBackground;

	private UI_Notifications _notifications;

	private bool _nativeNotificationsUnavailable;

	internal bool SuppressSmoke => _suppressSmoke.Value;

	internal bool SuppressSparks => _suppressSparks.Value;

	private ExplosionDetail CurrentExplosionDetail
	{
		get
		{
			try
			{
				ExplosionDetail value = _explosionDetail.Value;
				if (Enum.IsDefined(typeof(ExplosionDetail), value))
				{
					return value;
				}
			}
			catch (Exception)
			{
			}
			return ExplosionDetail.Minimal;
		}
	}

	internal int LiveModDynamite
	{
		get
		{
			int num = 0;
			foreach (Dynamite item in _modDynamite)
			{
				if ((Object)(object)item != (Object)null)
				{
					num++;
				}
			}
			return num;
		}
	}

	private void Awake()
	{
		//IL_04bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ce: Unknown result type (might be due to invalid IL or missing references)
		Log = ((BaseUnityPlugin)this).Logger;
		_enabledOnStart = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled On Start", false, "Start the game with the random dynamite spawner already enabled.");
		_toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "Toggle Key", (KeyCode)289, "Press this key to toggle the spawner on and off.");
		_manualBurstKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "Manual Burst Key", (KeyCode)290, "Press this key to drop one burst of dynamite right now, regardless of whether the spawner is on.");
		_intervalMin = ((BaseUnityPlugin)this).Config.Bind<float>("Spawn", "Interval Min (s)", 25f, "Minimum seconds between dynamite bursts.");
		_intervalMax = ((BaseUnityPlugin)this).Config.Bind<float>("Spawn", "Interval Max (s)", 70f, "Maximum seconds between dynamite bursts.");
		_countMin = ((BaseUnityPlugin)this).Config.Bind<int>("Spawn", "Count Min", 1, "Minimum number of dynamite per burst.");
		_countMax = ((BaseUnityPlugin)this).Config.Bind<int>("Spawn", "Count Max", 10, "Maximum number of dynamite per burst.");
		_heightMin = ((BaseUnityPlugin)this).Config.Bind<float>("Spawn", "Height Min", 6f, "Minimum spawn height above a player.");
		_heightMax = ((BaseUnityPlugin)this).Config.Bind<float>("Spawn", "Height Max", 16f, "Maximum spawn height above a player.");
		_spreadRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Spawn", "Spread Radius", 14f, "Horizontal scatter radius (metres) around the chosen player.");
		_burstSpreadTime = ((BaseUnityPlugin)this).Config.Bind<float>("Spawn", "Burst Spread Time (s)", 3f, "How long a burst takes to drop all of its dynamite. Spreading the drops out over a few seconds makes it arrive as a rolling rain instead of one clump. 0 drops everything at once.");
		_spawnOnEnable = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawn", "Burst Immediately On Enable", true, "Drop a burst the moment the spawner is toggled on.");
		_includeLocalPlayer = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawn", "Include Local Player", true, "Also drop dynamite above yourself. Disable to only troll everyone else.");
		_onlyAlive = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawn", "Only Above Alive Players", true, "Skip players who are already knocked out.");
		_lightFuses = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawn", "Light Fuses", true, "Light the fuse as soon as the dynamite spawns so it actually explodes.");
		_verbose = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Verbose Logging", true, "Log every spawned dynamite and skipped spawn. Useful for troubleshooting.");
		_suppressSmoke = ((BaseUnityPlugin)this).Config.Bind<bool>("Effects", "Suppress Smoke On Mod Dynamite", true, "Don't spawn the smoke trail for dynamite this mod spawned. Saves a lot of particles when a lot of dynamite is up. Vanilla dynamite is untouched.");
		_suppressSparks = ((BaseUnityPlugin)this).Config.Bind<bool>("Effects", "Suppress Sparks On Mod Dynamite", true, "Don't run the burning spark particles for dynamite this mod spawned.");
		_explosionDetail = ((BaseUnityPlugin)this).Config.Bind<ExplosionDetail>("Effects", "Explosion Detail", ExplosionDetail.Minimal, "How much of the explosion effect to keep for dynamite THIS MOD spawned. Vanilla dynamite is never affected. Minimal = sound and damage only, no visual objects at all. Particles = keeps the fireball/smoke burst but drops the 13 animated orbs. Full = completely untouched.");
		_randomiseFuse = ((BaseUnityPlugin)this).Config.Bind<bool>("Effects", "Randomise Fuse", true, "Give each spawned dynamite a slightly different fuse, so a burst explodes as a rolling barrage instead of 13xN animators hitting on the same frame.");
		_fuseJitterMin = ((BaseUnityPlugin)this).Config.Bind<float>("Effects", "Fuse Jitter Min (x)", 0.8f, "Lowest fuse multiplier used when Randomise Fuse is on.");
		_fuseJitterMax = ((BaseUnityPlugin)this).Config.Bind<float>("Effects", "Fuse Jitter Max (x)", 1.6f, "Highest fuse multiplier used when Randomise Fuse is on.");
		_maxLiveDynamite = ((BaseUnityPlugin)this).Config.Bind<int>("Effects", "Max Live Mod Dynamite", 20, "Safety cap. If this many of our dynamite are still un-exploded, a new burst is skipped instead of stacking up.");
		_messagesEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Messages", "Show Messages", true, "Show an on-screen message when the spawner is toggled or a manual burst is dropped.");
		_useGameNotifications = ((BaseUnityPlugin)this).Config.Bind<bool>("Messages", "Use Game Notifications", true, "Try to use PEAK's own notification popup first; falls back to a small overlay if unavailable.");
		_messageDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Messages", "Message Duration (s)", 3f, "How long an overlay message stays on screen.");
		_persistentIndicator = ((BaseUnityPlugin)this).Config.Bind<bool>("Messages", "Persistent Indicator", false, "Keep a small 'Random Dynamite: ON' label in the corner while the spawner is enabled.");
		if (_intervalMax.Value < _intervalMin.Value)
		{
			_intervalMax.Value = _intervalMin.Value;
		}
		_active = _enabledOnStart.Value;
		if (_active)
		{
			ScheduleNext();
		}
		Instance = this;
		try
		{
			Harmony.CreateAndPatchAll(typeof(Plugin), (string)null);
			Log.LogInfo((object)$"Harmony patches applied (smoke={_suppressSmoke.Value}, sparks={_suppressSparks.Value}, explosionDetail={CurrentExplosionDetail}, fuseJitter={_randomiseFuse.Value}).");
		}
		catch (Exception arg)
		{
			Log.LogError((object)$"Could not apply Harmony patches: {arg}");
		}
		Log.LogInfo((object)string.Format("{0} v{1} loaded. Toggle: {2}, manual burst: {3}. Config: BepInEx/config/{4}.cfg", "Random Dynamite", "1.7.0", _toggleKey.Value, _manualBurstKey.Value, "liam.RandomDynamite"));
	}

	private void Update()
	{
		//IL_002e: 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)
		try
		{
			if (!_loggedInputDiagnostics)
			{
				_loggedInputDiagnostics = true;
				LogInputDiagnostics();
			}
			MaybeAnnounceRoomJoin();
			PruneTrackedDynamite();
			ProcessPendingSpawns();
			if (KeyPressed(_toggleKey.Value))
			{
				_active = !_active;
				if (_active)
				{
					Log.LogInfo((object)"Random Dynamite: ON");
					ShowMessage("Random Dynamite: ON");
					if (_spawnOnEnable.Value)
					{
						SpawnBurst("enable");
					}
					ScheduleNext();
				}
				else
				{
					Log.LogInfo((object)"Random Dynamite: OFF");
					ShowMessage("Random Dynamite: OFF");
					_nextSpawnTime = float.MaxValue;
					if (_pendingSpawns.Count > 0)
					{
						Log.LogInfo((object)string.Format("{0}: cancelled {1} dynamite still queued from the last burst.", "Random Dynamite", _pendingSpawns.Count));
						_pendingSpawns.Clear();
					}
				}
			}
			if (KeyPressed(_manualBurstKey.Value))
			{
				Log.LogInfo((object)"Random Dynamite: manual burst requested");
				int num = SpawnBurst("manual");
				ShowMessage((num > 0) ? string.Format("{0}: dropping {1} dynamite", "Random Dynamite", num) : "Random Dynamite: no players to target");
			}
			if (_active && Time.time >= _nextSpawnTime)
			{
				SpawnBurst("auto");
				ScheduleNext();
			}
		}
		catch (Exception ex)
		{
			Log.LogError((object)ex);
		}
	}

	private void MaybeAnnounceRoomJoin()
	{
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		bool inRoom = PhotonNetwork.InRoom;
		if (!inRoom && _wasInRoom && _pendingSpawns.Count > 0)
		{
			Log.LogInfo((object)$"Left the room, discarding {_pendingSpawns.Count} queued dynamite.");
			_pendingSpawns.Clear();
		}
		if (inRoom && !_wasInRoom)
		{
			int num = 0;
			try
			{
				num = Character.AllCharacters?.Count ?? 0;
			}
			catch
			{
			}
			string text = ResolveDynamitePrefabName();
			bool flag = false;
			try
			{
				flag = (Object)(object)Resources.Load<GameObject>("0_Items/" + text) != (Object)null;
			}
			catch
			{
			}
			Log.LogInfo((object)$"Joined a room. isMaster={PhotonNetwork.IsMasterClient}, characters={num}, dynamitePrefab='{text}', prefabLoads={flag}");
			ShowMessage(string.Format("{0} ready - {1} toggle, {2} burst", "Random Dynamite", _toggleKey.Value, _manualBurstKey.Value));
		}
		else if (!inRoom && _wasInRoom)
		{
			_modDynamite.Clear();
		}
		_wasInRoom = inRoom;
	}

	private void PruneTrackedDynamite()
	{
		if (Time.time < _nextCleanupTime)
		{
			return;
		}
		_nextCleanupTime = Time.time + 5f;
		_staleDynamite.Clear();
		foreach (Dynamite item in _modDynamite)
		{
			if ((Object)(object)item == (Object)null)
			{
				_staleDynamite.Add(item);
			}
		}
		for (int i = 0; i < _staleDynamite.Count; i++)
		{
			_modDynamite.Remove(_staleDynamite[i]);
		}
		_staleDynamite.Clear();
	}

	internal bool IsModDynamite(Dynamite dynamite)
	{
		if ((Object)(object)dynamite == (Object)null)
		{
			return false;
		}
		return _modDynamite.Contains(dynamite);
	}

	private void ApplyExplosionDetail(Dynamite dynamite)
	{
		if ((Object)(object)dynamite == (Object)null || (Object)(object)dynamite.explosionPrefab == (Object)null)
		{
			return;
		}
		ExplosionDetail currentExplosionDetail = CurrentExplosionDetail;
		if (currentExplosionDetail == ExplosionDetail.Full)
		{
			return;
		}
		float num = ((dynamite.startingFuseTime > 0.01f) ? dynamite.startingFuseTime : 5f);
		float num2 = (_randomiseFuse.Value ? Mathf.Max(1f, _fuseJitterMax.Value) : 1f);
		float lifetime = num * num2 + 15f;
		try
		{
			dynamite.explosionPrefab = BuildCheapExplosion(dynamite.explosionPrefab, currentExplosionDetail, lifetime);
		}
		catch (Exception arg)
		{
			Log.LogWarning((object)$"Could not build a cheap explosion prefab, leaving the vanilla one: {arg}");
		}
	}

	private static bool DeactivateChild(GameObject target, GameObject root)
	{
		if ((Object)(object)target == (Object)null || (Object)(object)target == (Object)(object)root || !target.activeSelf)
		{
			return false;
		}
		target.SetActive(false);
		return true;
	}

	private GameObject BuildCheapExplosion(GameObject source, ExplosionDetail detail, float lifetime)
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		if (!_loggedExplosionPrefab)
		{
			_loggedExplosionPrefab = true;
			LogExplosionPrefabContents(source);
		}
		GameObject val = Object.Instantiate<GameObject>(source, new Vector3(0f, -100000f, 0f), Quaternion.identity);
		((Object)val).name = ((Object)source).name + "(CheapModCopy)";
		int num = 0;
		ExplosionEffect[] componentsInChildren = val.GetComponentsInChildren<ExplosionEffect>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			if (DeactivateChild(((Component)componentsInChildren[i]).gameObject, val))
			{
				num++;
			}
		}
		if (detail == ExplosionDetail.Minimal)
		{
			ParticleSystem[] componentsInChildren2 = val.GetComponentsInChildren<ParticleSystem>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				if (DeactivateChild(((Component)componentsInChildren2[i]).gameObject, val))
				{
					num++;
				}
			}
			Light[] componentsInChildren3 = val.GetComponentsInChildren<Light>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				if (DeactivateChild(((Component)componentsInChildren3[i]).gameObject, val))
				{
					num++;
				}
			}
			TrailRenderer[] componentsInChildren4 = val.GetComponentsInChildren<TrailRenderer>(true);
			for (int i = 0; i < componentsInChildren4.Length; i++)
			{
				if (DeactivateChild(((Component)componentsInChildren4[i]).gameObject, val))
				{
					num++;
				}
			}
			MeshRenderer[] componentsInChildren5 = val.GetComponentsInChildren<MeshRenderer>(true);
			for (int i = 0; i < componentsInChildren5.Length; i++)
			{
				if (DeactivateChild(((Component)componentsInChildren5[i]).gameObject, val))
				{
					num++;
				}
			}
		}
		RemoveAfterSeconds component = val.GetComponent<RemoveAfterSeconds>();
		if ((Object)(object)component != (Object)null && component.seconds < lifetime)
		{
			component.seconds = lifetime;
		}
		int num2 = 0;
		componentsInChildren = val.GetComponentsInChildren<ExplosionEffect>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			if (((Behaviour)componentsInChildren[i]).isActiveAndEnabled)
			{
				num2++;
			}
		}
		if (num2 > 0)
		{
			Log.LogWarning((object)$"Cheap explosion copy still has {num2} active ExplosionEffect component(s), so orbs will still spawn.");
		}
		if (_verbose.Value)
		{
			Log.LogInfo((object)($"Cheap explosion copy built ({detail}): {num} visual child object(s) deactivated, " + $"{num2} orb sources still active, lifetime {lifetime:F0}s."));
		}
		return val;
	}

	private void LogExplosionPrefabContents(GameObject source)
	{
		try
		{
			Log.LogInfo((object)("Explosion prefab '" + ((Object)source).name + "' components:"));
			Component[] componentsInChildren = source.GetComponentsInChildren<Component>(true);
			foreach (Component val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null)
				{
					Log.LogInfo((object)("    " + ((object)val).GetType().Name));
				}
			}
			ExplosionEffect componentInChildren = source.GetComponentInChildren<ExplosionEffect>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				int num = 1 + componentInChildren.explosionPointCount + componentInChildren.subExplosionPointCount * componentInChildren.explosionPointCount;
				Log.LogInfo((object)$"    -> {num} orb objects per explosion, each with its own Animator");
			}
			AudioSource[] componentsInChildren2 = source.GetComponentsInChildren<AudioSource>(true);
			foreach (AudioSource val2 in componentsInChildren2)
			{
				Log.LogInfo((object)$"    -> audio '{((Object)val2).name}' spatialBlend={val2.spatialBlend} (0 would play at any distance)");
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Could not log explosion prefab contents: " + ex.Message));
		}
	}

	private void LogInputDiagnostics()
	{
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		bool flag = false;
		try
		{
			flag = Keyboard.current != null;
		}
		catch
		{
		}
		Log.LogInfo((object)$"Input diagnostics: newInputSystemKeyboard={flag}, legacyInputAvailable={_legacyInputAvailable}, toggleKey={_toggleKey.Value}, burstKey={_manualBurstKey.Value}");
	}

	private void ScheduleNext()
	{
		float num = Mathf.Max(0.5f, _intervalMin.Value);
		float num2 = Mathf.Max(num, _intervalMax.Value);
		_nextSpawnTime = Time.time + Random.Range(num, num2);
	}

	private int SpawnBurst(string reason)
	{
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		if (!PhotonNetwork.InRoom)
		{
			Log.LogWarning((object)("Dynamite burst (" + reason + ") skipped: not in a Photon room yet."));
			return 0;
		}
		int num = _pendingSpawns.Count + LiveModDynamite;
		int num2 = Mathf.Max(1, _maxLiveDynamite.Value);
		if (num >= num2)
		{
			Log.LogWarning((object)$"Dynamite burst ({reason}) skipped: {num} of our dynamite are still outstanding (cap {num2}).");
			return 0;
		}
		int num3 = Random.Range(_countMin.Value, Mathf.Max(_countMin.Value, _countMax.Value) + 1);
		int num4 = 0;
		float num5 = Mathf.Max(0f, _burstSpreadTime.Value);
		float num6 = ((num3 > 1) ? (num5 / (float)(num3 - 1)) : 0f);
		float time = Time.time;
		for (int i = 0; i < num3; i++)
		{
			if (!TryGetSpawnPoint(out var point))
			{
				Log.LogWarning((object)$"Dynamite burst ({reason}): no valid player to spawn above after {num4} queued.");
				break;
			}
			float num7 = ((num6 <= 0f) ? 0f : ((float)i * num6 + Random.Range((0f - num6) * 0.3f, num6 * 0.3f)));
			_pendingSpawns.Enqueue(new PendingSpawn
			{
				Time = time + Mathf.Max(0f, num7),
				Position = point
			});
			num4++;
		}
		if (num4 > 0)
		{
			Log.LogInfo((object)$"Dynamite burst ({reason}): queued {num4} dynamite over {num5:F1}s ({_pendingSpawns.Count} still pending).");
		}
		return num4;
	}

	private void ProcessPendingSpawns()
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		while (_pendingSpawns.Count > 0 && _pendingSpawns.Peek().Time <= Time.time)
		{
			PendingSpawn pendingSpawn = _pendingSpawns.Dequeue();
			if (!PhotonNetwork.InRoom)
			{
				Log.LogWarning((object)"Dropped a queued dynamite: left the room.");
			}
			else
			{
				SpawnDynamite(pendingSpawn.Position);
			}
		}
	}

	private bool TryGetSpawnPoint(out Vector3 point)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//IL_0113: 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_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)
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Unknown result type (might be due to invalid IL or missing references)
		point = Vector3.zero;
		Targets.Clear();
		List<Character> allCharacters = Character.AllCharacters;
		if (allCharacters == null || allCharacters.Count == 0)
		{
			return false;
		}
		for (int i = 0; i < allCharacters.Count; i++)
		{
			Character val = allCharacters[i];
			if (!((Object)(object)val == (Object)null) && (_includeLocalPlayer.Value || !((Object)(object)val == (Object)(object)Character.localCharacter)) && (!_onlyAlive.Value || !((Object)(object)val.data != (Object)null) || !val.data.dead))
			{
				Targets.Add(val);
			}
		}
		if (Targets.Count == 0)
		{
			return false;
		}
		Vector3 center = Targets[Random.Range(0, Targets.Count)].Center;
		float num = Random.Range(_heightMin.Value, Mathf.Max(_heightMin.Value, _heightMax.Value));
		Vector2 val2 = Random.insideUnitCircle * _spreadRadius.Value;
		point = center + new Vector3(val2.x, num, val2.y);
		return true;
	}

	private bool SpawnDynamite(Vector3 position)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: 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)
		//IL_023f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: Expected O, but got Unknown
		//IL_015a: Unknown result type (might be due to invalid IL or missing references)
		//IL_015f: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Expected O, but got Unknown
		string text = ResolveDynamitePrefabName();
		string text2 = "0_Items/" + text;
		try
		{
			GameObject val = PhotonNetwork.Instantiate(text2, position, Random.rotation, (byte)0, (object[])null);
			if ((Object)(object)val == (Object)null)
			{
				Log.LogWarning((object)$"Instantiate returned null for '{text2}' at {position}.");
				return false;
			}
			Item component = val.GetComponent<Item>();
			PhotonView component2 = val.GetComponent<PhotonView>();
			Dynamite component3 = val.GetComponent<Dynamite>();
			if ((Object)(object)component3 != (Object)null)
			{
				_modDynamite.Add(component3);
				ApplyExplosionDetail(component3);
			}
			if ((Object)(object)component != (Object)null)
			{
				try
				{
					component.SetKinematicNetworked(false);
				}
				catch (Exception ex)
				{
					Log.LogWarning((object)("SetKinematicNetworked failed: " + ex.Message));
				}
			}
			if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null)
			{
				try
				{
					ItemInstanceData val2 = new ItemInstanceData(System.Guid.NewGuid());
					if (_randomiseFuse.Value && (Object)(object)component3 != (Object)null && component3.startingFuseTime > 0.01f)
					{
						float num = Mathf.Min(_fuseJitterMin.Value, _fuseJitterMax.Value);
						float num2 = Mathf.Max(_fuseJitterMin.Value, _fuseJitterMax.Value);
						float num3 = Random.Range(num, num2);
						float num4 = component3.startingFuseTime * num3;
						val2.RegisterEntry<FloatItemData>((DataEntryKey)10, new FloatItemData
						{
							Value = num4
						});
						if (_verbose.Value)
						{
							Log.LogInfo((object)$"Fuse jitter: {component3.startingFuseTime:F2}s x {num3:F2} = {num4:F2}s");
						}
					}
					ItemInstanceDataHandler.AddInstanceData(val2);
					component2.RPC("SetItemInstanceDataRPC", (RpcTarget)0, new object[1] { val2 });
				}
				catch (Exception ex2)
				{
					Log.LogWarning((object)("Could not set dynamite instance data: " + ex2.Message));
				}
			}
			if (_lightFuses.Value && (Object)(object)component3 != (Object)null)
			{
				try
				{
					component3.LightFlare();
				}
				catch (Exception ex3)
				{
					Log.LogWarning((object)("LightFlare failed: " + ex3.Message));
				}
			}
			if (_verbose.Value)
			{
				Log.LogInfo((object)$"Spawned dynamite '{text}' at {position}.");
			}
			return true;
		}
		catch (Exception arg)
		{
			Log.LogError((object)$"Failed to spawn dynamite: {arg}");
			return false;
		}
	}

	private string ResolveDynamitePrefabName()
	{
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		if (!string.IsNullOrEmpty(_dynamitePrefabName))
		{
			return _dynamitePrefabName;
		}
		try
		{
			Dynamite[] array = Resources.FindObjectsOfTypeAll<Dynamite>();
			if (array != null)
			{
				for (int i = 0; i < 2; i++)
				{
					if (!string.IsNullOrEmpty(_dynamitePrefabName))
					{
						break;
					}
					foreach (Dynamite val in array)
					{
						if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null)
						{
							continue;
						}
						Scene scene = ((Component)val).gameObject.scene;
						bool flag = ((Scene)(ref scene)).IsValid();
						if (!(i == 0 && flag))
						{
							string text = ItemPrefabName(val);
							if (!string.IsNullOrEmpty(text))
							{
								_dynamitePrefabName = text;
								break;
							}
						}
					}
				}
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Could not resolve Dynamite prefab name: " + ex.Message));
		}
		if (string.IsNullOrEmpty(_dynamitePrefabName))
		{
			_dynamitePrefabName = "Dynamite";
			Log.LogWarning((object)"Falling back to hard-coded dynamite prefab name 'Dynamite'.");
		}
		else
		{
			Log.LogInfo((object)("Resolved dynamite prefab name: '" + _dynamitePrefabName + "'."));
		}
		return _dynamitePrefabName;
	}

	private static string ItemPrefabName(Dynamite dynamite)
	{
		Item component = ((Component)dynamite).GetComponent<Item>();
		GameObject val = (((Object)(object)component != (Object)null) ? ((Component)component).gameObject : ((Component)dynamite).gameObject);
		string text = (((Object)(object)val != (Object)null) ? ((Object)val).name : null);
		if (string.IsNullOrEmpty(text))
		{
			return null;
		}
		if (text.EndsWith("(Clone)", StringComparison.Ordinal))
		{
			text = text.Substring(0, text.Length - "(Clone)".Length).Trim();
		}
		return text;
	}

	private void ShowMessage(string text)
	{
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		if (!_messagesEnabled.Value || string.IsNullOrEmpty(text))
		{
			return;
		}
		if (_useGameNotifications.Value && !_nativeNotificationsUnavailable)
		{
			try
			{
				if ((Object)(object)_notifications == (Object)null)
				{
					UI_Notifications[] array = Resources.FindObjectsOfTypeAll<UI_Notifications>();
					if (array != null)
					{
						foreach (UI_Notifications val in array)
						{
							if ((Object)(object)val == (Object)null)
							{
								continue;
							}
							GameObject gameObject = ((Component)val).gameObject;
							if ((Object)(object)gameObject != (Object)null)
							{
								Scene scene = gameObject.scene;
								if (((Scene)(ref scene)).IsValid() && gameObject.activeInHierarchy)
								{
									_notifications = val;
									break;
								}
							}
						}
					}
				}
				if ((Object)(object)_notifications != (Object)null)
				{
					_notifications.AddNotification(text);
					return;
				}
			}
			catch
			{
				_nativeNotificationsUnavailable = true;
				_notifications = null;
			}
		}
		_toastText = text;
		_toastUntil = Time.time + Mathf.Max(0.5f, _messageDuration.Value);
	}

	private void OnGUI()
	{
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			int num;
			if (_toastText != null)
			{
				num = ((Time.time < _toastUntil) ? 1 : 0);
				if (num != 0)
				{
					goto IL_0030;
				}
			}
			else
			{
				num = 0;
			}
			if (_persistentIndicator.Value && _active)
			{
				goto IL_0030;
			}
			goto IL_0036;
			IL_0030:
			EnsureStyles();
			goto IL_0036;
			IL_0036:
			if (num != 0)
			{
				Rect val = new Rect(((float)Screen.width - 520f) * 0.5f, (float)Screen.height * 0.12f, 520f, 46f);
				GUI.DrawTexture(val, (Texture)(object)_toastBackground);
				GUI.Label(val, _toastText, _toastStyle);
			}
			if (_persistentIndicator.Value && _active)
			{
				GUI.Label(new Rect((float)Screen.width - 260f, (float)Screen.height - 42f, 248f, 30f), "Random Dynamite: ON", _indicatorStyle);
			}
		}
		catch
		{
		}
	}

	private void EnsureStyles()
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Expected O, but got Unknown
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Expected O, but got Unknown
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Expected O, but got Unknown
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		if (_toastStyle == null)
		{
			_toastBackground = new Texture2D(1, 1);
			_toastBackground.SetPixel(0, 0, new Color(0f, 0f, 0f, 0.72f));
			_toastBackground.Apply();
			_toastStyle = new GUIStyle(GUI.skin.label);
			_toastStyle.alignment = (TextAnchor)4;
			_toastStyle.fontSize = 22;
			_toastStyle.fontStyle = (FontStyle)1;
			_toastStyle.normal.textColor = Color.white;
			_indicatorStyle = new GUIStyle(GUI.skin.label);
			_indicatorStyle.alignment = (TextAnchor)5;
			_indicatorStyle.fontSize = 16;
			_indicatorStyle.fontStyle = (FontStyle)1;
			_indicatorStyle.normal.textColor = new Color(1f, 0.62f, 0.2f, 1f);
		}
	}

	private unsafe bool KeyPressed(KeyCode key)
	{
		//IL_0022: 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)
		bool flag = false;
		try
		{
			Keyboard current = Keyboard.current;
			if (current != null && Enum.TryParse<Key>(((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString(), out Key result))
			{
				flag = ((ButtonControl)current[result]).wasPressedThisFrame;
			}
		}
		catch
		{
		}
		if (!flag && _legacyInputAvailable)
		{
			try
			{
				flag = Input.GetKeyDown(key);
			}
			catch
			{
				_legacyInputAvailable = false;
			}
		}
		return flag;
	}
}