Decompiled source of The Bubble Gun v0.1.2

BepInEx\plugins\BubbleGun\BubbleGun.dll

Decompiled 14 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BubbleGun.Combat;
using BubbleGun.Weapon;
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("BubbleGun")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Bubble Gun weapon mod for R.E.P.O. - fires rainbow bubbles that pop, arm on hard surfaces, and chain-detonate.")]
[assembly: AssemblyFileVersion("0.1.2.0")]
[assembly: AssemblyInformationalVersion("0.1.2")]
[assembly: AssemblyProduct("BubbleGun")]
[assembly: AssemblyTitle("BubbleGun")]
[assembly: AssemblyVersion("0.1.2.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 BubbleGun
{
	[BepInPlugin("com.amgru.bubblegun", "BubbleGun", "0.1.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.amgru.bubblegun";

		public const string PluginName = "BubbleGun";

		public const string PluginVersion = "0.1.2";

		internal static ConfigEntry<bool> ModEnabled = null;

		internal static ConfigEntry<int> ExplosionDamage = null;

		internal static ConfigEntry<float> ExplosionRadius = null;

		internal static ConfigEntry<float> ExplosionKnockback = null;

		internal static ConfigEntry<float> ChainReactionRadius = null;

		internal static ConfigEntry<float> ArmedLifetime = null;

		internal static ConfigEntry<float> TankCapacity = null;

		internal static ConfigEntry<float> TankDrainRate = null;

		internal static ConfigEntry<float> TankRechargeRate = null;

		internal static ConfigEntry<float> BubbleSpeed = null;

		private Harmony? harmony;

		internal static string PluginDirectory { get; private set; } = string.Empty;


		private void Awake()
		{
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Expected O, but got Unknown
			PluginDirectory = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? string.Empty;
			ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enables or disables the Bubble Gun.");
			ExplosionDamage = ((BaseUnityPlugin)this).Config.Bind<int>("Explosion", "Damage", 24, "Damage dealt to enemies by a bubble pop. Tuned as a moderate 4/10 blast.");
			ExplosionRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Explosion", "Radius", 2.2f, "Radius of the minor bubble explosion.");
			ExplosionKnockback = ((BaseUnityPlugin)this).Config.Bind<float>("Explosion", "Knockback", 24f, "Impulse applied to enemies hit by bubble explosions.");
			ChainReactionRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Explosion", "ChainReactionRadius", 3.6f, "Distance at which a popping bubble detonates other nearby bubbles.");
			ArmedLifetime = ((BaseUnityPlugin)this).Config.Bind<float>("Explosion", "ArmedLifetime", 60f, "Seconds a bubble remains as a static bomb after touching inorganic geometry.");
			TankCapacity = ((BaseUnityPlugin)this).Config.Bind<float>("Gun", "TankCapacity", 100f, "Maximum Bubble tank capacity.");
			TankDrainRate = ((BaseUnityPlugin)this).Config.Bind<float>("Gun", "DrainRate", 4f, "Bubble units drained per second while firing.");
			TankRechargeRate = ((BaseUnityPlugin)this).Config.Bind<float>("Gun", "RechargeRate", 0f, "Bubble units recharged per second when not firing. Bubble Gun does not auto-recharge.");
			BubbleSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Gun", "BubbleSpeed", 5.5f, "Initial speed of bubble projectiles in m/s.");
			BubbleGunRuntime.Enabled = ModEnabled.Value;
			BubbleGunRuntime.PluginDirectory = PluginDirectory;
			harmony = new Harmony("com.amgru.bubblegun");
			harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} v{1} loaded. Enabled={2}", "BubbleGun", "0.1.2", ModEnabled.Value));
		}

		private void OnDestroy()
		{
			Harmony? obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}
	}
}
namespace BubbleGun.Patches
{
	[HarmonyPatch(typeof(ItemGun), "Shoot")]
	internal static class ItemGunShootPatch
	{
		private static bool Prefix(ItemGun __instance)
		{
			if ((((Component)__instance).GetComponent<ItemAttributes>() ?? ((Component)__instance).GetComponentInChildren<ItemAttributes>(true) ?? ((Component)__instance).GetComponentInParent<ItemAttributes>())?.item?.itemName != "Bubble Gun")
			{
				return true;
			}
			BubbleGunController.OnItemGunShoot(__instance);
			return false;
		}
	}
	[HarmonyPatch(typeof(ItemGun), "Update")]
	internal static class ItemGunUpdatePatch
	{
		private static void Postfix(ItemGun __instance)
		{
			if ((((Component)__instance).GetComponent<ItemAttributes>() ?? ((Component)__instance).GetComponentInChildren<ItemAttributes>(true) ?? ((Component)__instance).GetComponentInParent<ItemAttributes>())?.item?.itemName != "Bubble Gun")
			{
				return;
			}
			Renderer[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				string name = ((object)val).GetType().Name;
				if ((name == "LineRenderer" || name == "TrailRenderer") && val.enabled)
				{
					val.enabled = false;
				}
			}
			Component[] componentsInChildren2 = ((Component)__instance).GetComponentsInChildren<Component>(true);
			bool flag = default(bool);
			foreach (Component val2 in componentsInChildren2)
			{
				if (!((Object)(object)val2 == (Object)null) && !(((object)val2).GetType().Name != "ParticleSystem"))
				{
					object obj = ((object)val2).GetType().GetProperty("isPlaying")?.GetValue(val2);
					int num;
					if (obj is bool)
					{
						flag = (bool)obj;
						num = 1;
					}
					else
					{
						num = 0;
					}
					if (((uint)num & (flag ? 1u : 0u)) != 0)
					{
						((object)val2).GetType().GetMethod("Stop", Type.EmptyTypes)?.Invoke(val2, null);
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(PhysGrabObject), "Update")]
	internal static class PhysGrabObjectUpdatePatch
	{
		private static void Postfix(PhysGrabObject __instance)
		{
			BubbleGunController.OnPhysGrabObjectUpdate(__instance);
		}
	}
	[HarmonyPatch(typeof(PlayerController), "Start")]
	internal static class PlayerControllerStartPatch
	{
		private static void Postfix(PlayerController __instance)
		{
		}
	}
}
namespace BubbleGun.Combat
{
	internal static class BubbleCombat
	{
		private static readonly FieldInfo EnemyHasHealthField = AccessTools.Field(typeof(Enemy), "HasHealth");

		private static readonly FieldInfo EnemyHealthField = AccessTools.Field(typeof(Enemy), "Health");

		private static readonly FieldInfo EnemyHasRigidbodyField = AccessTools.Field(typeof(Enemy), "HasRigidbody");

		private static readonly FieldInfo EnemyRigidbodyField = AccessTools.Field(typeof(Enemy), "Rigidbody");

		private static readonly FieldInfo EnemyRbField = AccessTools.Field(typeof(EnemyRigidbody), "rb");

		internal static Enemy? FindEnemy(Collider collider)
		{
			Enemy componentInParent = ((Component)collider).GetComponentInParent<Enemy>();
			if ((Object)(object)componentInParent != (Object)null && Object.op_Implicit((Object)(object)componentInParent))
			{
				return componentInParent;
			}
			EnemyRigidbody componentInParent2 = ((Component)collider).GetComponentInParent<EnemyRigidbody>();
			if ((Object)(object)componentInParent2 != (Object)null && (Object)(object)componentInParent2.enemy != (Object)null && Object.op_Implicit((Object)(object)componentInParent2.enemy))
			{
				return componentInParent2.enemy;
			}
			if (!((Object)(object)collider.attachedRigidbody != (Object)null))
			{
				return null;
			}
			return ((Component)collider.attachedRigidbody).GetComponent<EnemyRigidbody>()?.enemy;
		}

		internal static PlayerController? FindPlayer(Collider collider)
		{
			PlayerController componentInParent = ((Component)collider).GetComponentInParent<PlayerController>();
			if ((Object)(object)componentInParent != (Object)null && Object.op_Implicit((Object)(object)componentInParent))
			{
				return componentInParent;
			}
			PlayerAvatar componentInParent2 = ((Component)collider).GetComponentInParent<PlayerAvatar>();
			if ((Object)(object)componentInParent2 != (Object)null && Object.op_Implicit((Object)(object)componentInParent2))
			{
				PlayerController val = ((Component)componentInParent2).GetComponent<PlayerController>() ?? ((Component)componentInParent2).GetComponentInParent<PlayerController>();
				if ((Object)(object)val != (Object)null && Object.op_Implicit((Object)(object)val))
				{
					return val;
				}
			}
			return null;
		}

		internal static PlayerAvatar? FindPlayerAvatar(Collider collider)
		{
			PlayerController val = FindPlayer(collider);
			if ((Object)(object)val != (Object)null && Object.op_Implicit((Object)(object)val) && (Object)(object)val.playerAvatarScript != (Object)null && Object.op_Implicit((Object)(object)val.playerAvatarScript))
			{
				return val.playerAvatarScript;
			}
			PlayerAvatar componentInParent = ((Component)collider).GetComponentInParent<PlayerAvatar>();
			if ((Object)(object)componentInParent != (Object)null && Object.op_Implicit((Object)(object)componentInParent))
			{
				return componentInParent;
			}
			if ((Object)(object)collider.attachedRigidbody != (Object)null)
			{
				componentInParent = ((Component)collider.attachedRigidbody).GetComponent<PlayerAvatar>() ?? ((Component)collider.attachedRigidbody).GetComponentInParent<PlayerAvatar>();
				if ((Object)(object)componentInParent != (Object)null && Object.op_Implicit((Object)(object)componentInParent))
				{
					return componentInParent;
				}
			}
			return null;
		}

		internal static void DamageEnemy(Enemy enemy, int damage, Vector3 hitPosition)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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 (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			Vector3 val = ((Component)enemy).transform.position - hitPosition;
			Vector3 val2 = ((Vector3)(ref val)).normalized;
			if (((Vector3)(ref val2)).sqrMagnitude < 0.01f)
			{
				val2 = Vector3.forward;
			}
			object value = EnemyHasHealthField.GetValue(enemy);
			bool flag = default(bool);
			int num;
			if (value is bool)
			{
				flag = (bool)value;
				num = 1;
			}
			else
			{
				num = 0;
			}
			if (((uint)num & (flag ? 1u : 0u)) != 0)
			{
				object? value2 = EnemyHealthField.GetValue(enemy);
				EnemyHealth val3 = (EnemyHealth)((value2 is EnemyHealth) ? value2 : null);
				if (val3 != null)
				{
					val3.Hurt(Mathf.Max(0, damage), val2);
					Debug.Log((object)$"[BubbleGun] Bubble tick: {damage} damage to {((Object)enemy).name}.");
					return;
				}
			}
			Debug.Log((object)$"[BubbleGun] Would deal {damage} to {((Object)enemy).name} but no EnemyHealth hook available.");
		}

		internal static void HealPlayer(PlayerAvatar playerAvatar, int amount)
		{
			if (SemiFunc.IsMasterClientOrSingleplayer())
			{
				PlayerHealth val = playerAvatar.playerHealth ?? ((Component)playerAvatar).GetComponent<PlayerHealth>() ?? ((Component)playerAvatar).GetComponentInChildren<PlayerHealth>(true) ?? ((Component)playerAvatar).GetComponentInParent<PlayerHealth>();
				if ((Object)(object)val != (Object)null && Object.op_Implicit((Object)(object)val))
				{
					val.HealOther(Mathf.Max(0, amount), true);
					playerAvatar.HealedOther();
					Debug.Log((object)$"[BubbleGun] Bubble tick: healed {amount} HP on {((Object)playerAvatar).name}.");
				}
				else
				{
					Debug.Log((object)$"[BubbleGun] Would heal {amount} HP on {((Object)playerAvatar).name} but no PlayerHealth component was found.");
				}
			}
		}

		internal static Rigidbody? GetEnemyRigidbody(Enemy enemy)
		{
			object value = EnemyHasRigidbodyField.GetValue(enemy);
			bool flag = default(bool);
			int num;
			if (value is bool)
			{
				flag = (bool)value;
				num = 1;
			}
			else
			{
				num = 0;
			}
			if (((uint)num & (flag ? 1u : 0u)) != 0)
			{
				object? value2 = EnemyRigidbodyField.GetValue(enemy);
				EnemyRigidbody val = (EnemyRigidbody)((value2 is EnemyRigidbody) ? value2 : null);
				if (val != null)
				{
					object? value3 = EnemyRbField.GetValue(val);
					Rigidbody val2 = (Rigidbody)((value3 is Rigidbody) ? value3 : null);
					if (val2 != null)
					{
						return val2;
					}
				}
			}
			return null;
		}
	}
}
namespace BubbleGun.Weapon
{
	public sealed class BubbleBomb : MonoBehaviour
	{
		private enum BubbleState
		{
			Floating,
			Armed,
			Detonated
		}

		private static readonly List<BubbleBomb> ActiveBubbles = new List<BubbleBomb>();

		private static readonly HashSet<int> SeenEnemies = new HashSet<int>();

		private BubbleState state;

		private Rigidbody? rb;

		private Renderer? bubbleRenderer;

		private Material? bubbleMaterial;

		private float spawnTime;

		private float expiresAt;

		private float armedLifetime;

		private float explosionRadius;

		private float chainReactionRadius;

		private int explosionDamage;

		private float explosionKnockback;

		private BubbleGunNetworkProxy? networkProxy;

		private int bubbleId;

		private Transform? ignoredRoot;

		private Vector3 armedSurfaceNormal = Vector3.up;

		private float hueOffset;

		private Vector3 baseScale = Vector3.one;

		private float nextArmedEnemyCheckAt;

		private const float ContactGraceSeconds = 0.16f;

		private const float ContactRadius = 0.14f;

		private const float ArmedEnemyTriggerRadius = 0.75f;

		private const float BubbleWeight = 0.11f;

		private const float VerticalBob = 0.06f;

		private const float SideDrift = 0.055f;

		internal void Initialize(float flightLifetime, float armedLifetime, float explosionRadius, float chainReactionRadius, int explosionDamage, float explosionKnockback, BubbleGunNetworkProxy? networkProxy, int bubbleId, Transform? ignoredRoot)
		{
			//IL_00b1: 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)
			spawnTime = Time.time;
			expiresAt = Time.time + Mathf.Max(0.25f, flightLifetime);
			this.armedLifetime = Mathf.Max(1f, armedLifetime);
			this.explosionRadius = Mathf.Clamp(explosionRadius, 0.5f, 8f);
			this.chainReactionRadius = Mathf.Clamp(chainReactionRadius, 0.5f, 10f);
			this.explosionDamage = Mathf.Clamp(explosionDamage, 0, 24);
			this.explosionKnockback = Mathf.Clamp(explosionKnockback, 0f, 80f);
			this.networkProxy = networkProxy;
			this.bubbleId = bubbleId;
			this.ignoredRoot = ignoredRoot;
			hueOffset = Random.value;
			baseScale = ((Component)this).transform.localScale;
			rb = ((Component)this).GetComponent<Rigidbody>();
			bubbleRenderer = ((Component)this).GetComponent<Renderer>();
			bubbleMaterial = (((Object)(object)bubbleRenderer != (Object)null) ? bubbleRenderer.material : null);
			ActiveBubbles.Add(this);
		}

		private void OnDestroy()
		{
			ActiveBubbles.Remove(this);
		}

		private void Update()
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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)
			AnimateRainbowShell();
			if (state == BubbleState.Floating && (Object)(object)rb != (Object)null)
			{
				float num = Mathf.Sin((Time.time + hueOffset) * 2.1f) * 0.055f;
				float num2 = Mathf.Sin((Time.time + hueOffset) * 3.4f) * 0.06f;
				rb.AddForce(Vector3.down * 0.11f + Vector3.up * num2 + ((Component)this).transform.right * num, (ForceMode)5);
			}
			else if (state == BubbleState.Armed && Time.time >= nextArmedEnemyCheckAt)
			{
				nextArmedEnemyCheckAt = Time.time + 0.08f;
				CheckArmedEnemyContact();
			}
			if (Time.time >= expiresAt)
			{
				if (state == BubbleState.Armed)
				{
					Detonate(chainTriggered: false);
				}
				else
				{
					Object.Destroy((Object)(object)((Component)this).gameObject);
				}
			}
			else if (Time.time - spawnTime >= 0.16f && state == BubbleState.Floating)
			{
				CheckContacts();
			}
		}

		private void OnTriggerEnter(Collider other)
		{
			if (Time.time - spawnTime < 0.16f)
			{
				return;
			}
			if (state == BubbleState.Armed)
			{
				if ((Object)(object)other != (Object)null && (Object)(object)BubbleCombat.FindEnemy(other) != (Object)null)
				{
					Detonate(chainTriggered: false);
				}
			}
			else if (state == BubbleState.Floating)
			{
				HandleContact(other);
			}
		}

		internal void ChainDetonate(Vector3 sourcePosition)
		{
			//IL_0010: 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)
			if (state != BubbleState.Detonated)
			{
				float num = Mathf.Clamp(Vector3.Distance(((Component)this).transform.position, sourcePosition) * 0.09f, 0.05f, 0.5f);
				((MonoBehaviour)this).Invoke("DetonateFromChain", num);
			}
		}

		private void DetonateFromChain()
		{
			Detonate(chainTriggered: true);
		}

		private void CheckContacts()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Collider[] array = Physics.OverlapSphere(((Component)this).transform.position, 0.14f, -1, (QueryTriggerInteraction)2);
			foreach (Collider val in array)
			{
				if ((Object)(object)val != (Object)null && HandleContact(val))
				{
					break;
				}
			}
		}

		private void CheckArmedEnemyContact()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Collider[] array = Physics.OverlapSphere(((Component)this).transform.position, 0.75f, -1, (QueryTriggerInteraction)2);
			foreach (Collider val in array)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)BubbleCombat.FindPlayerAvatar(val) != (Object)null) && (Object)(object)BubbleCombat.FindEnemy(val) != (Object)null)
				{
					Detonate(chainTriggered: false);
					break;
				}
			}
		}

		private bool HandleContact(Collider other)
		{
			if ((Object)(object)other == (Object)null || (Object)(object)((Component)other).transform == (Object)(object)((Component)this).transform || (Object)(object)((Component)other).GetComponentInParent<BubbleBomb>() == (Object)(object)this)
			{
				return false;
			}
			if (IsIgnoredCollider(other) || (Object)(object)BubbleCombat.FindPlayerAvatar(other) != (Object)null)
			{
				return false;
			}
			if ((Object)(object)BubbleCombat.FindEnemy(other) != (Object)null)
			{
				Detonate(chainTriggered: false);
				return true;
			}
			if (other.isTrigger)
			{
				return false;
			}
			return ArmOnSurface(other);
		}

		private bool ArmOnSurface(Collider surface)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			if (state != 0)
			{
				return false;
			}
			Vector3 val = surface.ClosestPoint(((Component)this).transform.position);
			Vector3 val2 = ((Component)this).transform.position - val;
			float magnitude = ((Vector3)(ref val2)).magnitude;
			float num = Mathf.Max(0.04f, ((Component)this).transform.lossyScale.x * 0.65f);
			if (magnitude < 0.02f || magnitude > num)
			{
				return false;
			}
			state = BubbleState.Armed;
			expiresAt = Time.time + armedLifetime;
			armedSurfaceNormal = val2 / magnitude;
			((Component)this).transform.position = val + armedSurfaceNormal * Mathf.Max(0.025f, ((Component)this).transform.lossyScale.x * 0.32f);
			if ((Object)(object)rb != (Object)null)
			{
				rb.velocity = Vector3.zero;
				rb.angularVelocity = Vector3.zero;
				rb.isKinematic = true;
			}
			Debug.Log((object)$"[BubbleGun] Bubble armed on {((Object)surface).name} for {armedLifetime:0.0}s.");
			return true;
		}

		private bool IsIgnoredCollider(Collider other)
		{
			if ((Object)(object)ignoredRoot != (Object)null && ((Component)other).transform.IsChildOf(ignoredRoot))
			{
				return true;
			}
			ItemAttributes componentInParent = ((Component)other).GetComponentInParent<ItemAttributes>();
			if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.item != (Object)null)
			{
				return componentInParent.item.itemName == "Bubble Gun";
			}
			return false;
		}

		private void Detonate(bool chainTriggered)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			if (state != BubbleState.Detonated)
			{
				state = BubbleState.Detonated;
				Vector3 position = ((Component)this).transform.position;
				SpawnExplosionVisual(position, chainTriggered, explosionRadius);
				ApplyExplosionDamage(position);
				TriggerNearbyBubbles(position);
				networkProxy?.BroadcastBubblePop(bubbleId, position, explosionRadius, chainTriggered);
				Debug.Log((object)$"[BubbleGun] Bubble popped at {position}; radius={explosionRadius:0.0}, chain={chainTriggered}.");
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}

		private void ApplyExplosionDamage(Vector3 position)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				networkProxy?.RequestExplosionDamage(position, explosionRadius, explosionDamage, explosionKnockback);
				return;
			}
			SeenEnemies.Clear();
			Collider[] array = Physics.OverlapSphere(position, explosionRadius, -1, (QueryTriggerInteraction)2);
			foreach (Collider val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Enemy val2 = BubbleCombat.FindEnemy(val);
				if ((Object)(object)val2 != (Object)null && Object.op_Implicit((Object)(object)val2) && SeenEnemies.Add(((Object)val2).GetInstanceID()))
				{
					BubbleCombat.DamageEnemy(val2, explosionDamage, position);
					Rigidbody enemyRigidbody = BubbleCombat.GetEnemyRigidbody(val2);
					if ((Object)(object)enemyRigidbody != (Object)null && Object.op_Implicit((Object)(object)enemyRigidbody))
					{
						enemyRigidbody.AddExplosionForce(explosionKnockback, position, explosionRadius, 0.45f, (ForceMode)1);
					}
				}
			}
		}

		private void TriggerNearbyBubbles(Vector3 position)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			for (int num = ActiveBubbles.Count - 1; num >= 0; num--)
			{
				BubbleBomb bubbleBomb = ActiveBubbles[num];
				if (!((Object)(object)bubbleBomb == (Object)null) && !((Object)(object)bubbleBomb == (Object)(object)this) && bubbleBomb.state != BubbleState.Detonated && Vector3.Distance(position, ((Component)bubbleBomb).transform.position) <= chainReactionRadius)
				{
					bubbleBomb.ChainDetonate(position);
				}
			}
		}

		private void AnimateRainbowShell()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)bubbleMaterial == (Object)null))
			{
				Color val = Color.HSVToRGB(Mathf.Repeat(hueOffset + Time.time * 0.12f, 1f), 0.55f, 1f);
				val.a = ((state == BubbleState.Armed) ? 0.46f : 0.34f);
				bubbleMaterial.color = val;
				if (bubbleMaterial.HasProperty("_EmissionColor"))
				{
					bubbleMaterial.SetColor("_EmissionColor", val * ((state == BubbleState.Armed) ? 0.55f : 0.35f));
				}
				float num = ((state == BubbleState.Armed) ? (1f + Mathf.Sin(Time.time * 8f) * 0.035f) : (1f + Mathf.Sin(Time.time * 2.2f + hueOffset) * 0.018f));
				((Component)this).transform.localScale = baseScale * num;
			}
		}

		private static void SpawnExplosionVisual(Vector3 position, bool chainTriggered, float explosionRadius)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = GameObject.CreatePrimitive((PrimitiveType)0);
			((Object)obj).name = (chainTriggered ? "BubbleChainPopVfx" : "BubblePopVfx");
			obj.transform.position = position;
			obj.transform.localScale = Vector3.one * 0.18f;
			Collider val = default(Collider);
			if (obj.TryGetComponent<Collider>(ref val))
			{
				Object.Destroy((Object)(object)val);
			}
			Material material = obj.GetComponent<Renderer>().material;
			material.color = (chainTriggered ? new Color(1f, 0.62f, 0.95f, 0.58f) : new Color(0.78f, 0.95f, 1f, 0.42f));
			TrySetTransparent(material);
			float targetScale = (chainTriggered ? Mathf.Max(2.8f, explosionRadius * 1.45f) : 2.2f);
			float lifetime = (chainTriggered ? 0.42f : 0.28f);
			obj.AddComponent<BubblePopVfx>().Initialize(lifetime, targetScale);
		}

		private static void TrySetTransparent(Material mat)
		{
			try
			{
				mat.SetFloat("_Mode", 3f);
				mat.SetInt("_SrcBlend", 5);
				mat.SetInt("_DstBlend", 10);
				mat.SetInt("_ZWrite", 0);
				mat.DisableKeyword("_ALPHATEST_ON");
				mat.EnableKeyword("_ALPHABLEND_ON");
				mat.DisableKeyword("_ALPHAPREMULTIPLY_ON");
				mat.renderQueue = 3000;
			}
			catch
			{
			}
			try
			{
				mat.SetFloat("_Surface", 1f);
				mat.SetFloat("_Blend", 0f);
				mat.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");
			}
			catch
			{
			}
		}
	}
	public sealed class BubbleGunController : MonoBehaviour
	{
		private sealed class HeldGunState
		{
			public float BubbleTank;

			public float FireRequestedUntil;

			public float SprayAccumulator;

			public float Pressure;

			public float NextNetworkSprayAt;

			public bool Initialized;

			public Component? Battery;
		}

		private static readonly FieldInfo? PlayerAvatarIsLocalField = typeof(PlayerAvatar).GetField("isLocal", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo? GrabbedPhysGrabObjectField = typeof(PhysGrabber).GetField("grabbedPhysGrabObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo? HeldByLocalPlayerField = typeof(PhysGrabObject).GetField("heldByLocalPlayer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo? ToggleImpulseField = typeof(ItemToggle).GetField("toggleImpulse", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly Dictionary<int, HeldGunState> HeldGunStates = new Dictionary<int, HeldGunState>();

		private static readonly Dictionary<Type, FieldInfo?> BatteryLifeFields = new Dictionary<Type, FieldInfo>();

		private static readonly Dictionary<Type, FieldInfo?> BatteryActiveFields = new Dictionary<Type, FieldInfo>();

		private PlayerController? playerController;

		private float BubbleTank;

		private bool inputUnavailableLogged;

		private const float GlobFireInterval = 0.05f;

		private const float TriggerRequestWindow = 0.18f;

		private const float PressureRisePerSecond = 7.5f;

		private const float PressureFallPerSecond = 5.5f;

		private const float SprayDropletsPerSecond = 18f;

		private const int MaxDropletsPerFrame = 2;

		private const float BubbleFlightLifetime = 7f;

		private const float BubbleLaunchUpward = 0.22f;

		private const float SprayConeAngle = 5.5f;

		private const float BubbleRangeMultiplier = 0.9f;

		private static Material? _BubbleMaterial;

		internal const string BubbleGunItemName = "Bubble Gun";

		private const string BarrelMarkerName = "BubbleGun Barrel Origin";

		public float TankFraction
		{
			get
			{
				if (!(Plugin.TankCapacity.Value > 0f))
				{
					return 0f;
				}
				return BubbleTank / Plugin.TankCapacity.Value;
			}
		}

		internal static void OnItemGunShoot(ItemGun gun)
		{
			if (BubbleGunRuntime.Enabled && !((Object)(object)gun == (Object)null) && Object.op_Implicit((Object)(object)gun))
			{
				PhysGrabObject val = ((Component)gun).GetComponent<PhysGrabObject>() ?? ((Component)gun).GetComponentInParent<PhysGrabObject>();
				int key = (((Object)(object)val != (Object)null) ? ((Object)val).GetInstanceID() : ((Object)gun).GetInstanceID());
				if (!HeldGunStates.TryGetValue(key, out HeldGunState value))
				{
					value = new HeldGunState
					{
						BubbleTank = Plugin.TankCapacity.Value,
						Initialized = true
					};
					HeldGunStates[key] = value;
				}
				value.FireRequestedUntil = Time.time + 0.18f;
				value.Pressure = Mathf.Max(value.Pressure, 0.25f);
			}
		}

		internal static void OnPhysGrabObjectUpdate(PhysGrabObject physGrabObject)
		{
			if (!BubbleGunRuntime.Enabled || (Object)(object)physGrabObject == (Object)null || !Object.op_Implicit((Object)(object)physGrabObject))
			{
				return;
			}
			ItemAttributes val = ((Component)physGrabObject).GetComponent<ItemAttributes>() ?? ((Component)physGrabObject).GetComponentInChildren<ItemAttributes>(true) ?? ((Component)physGrabObject).GetComponentInParent<ItemAttributes>();
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val.item == (Object)null) && !(val.item.itemName != "Bubble Gun"))
			{
				int instanceID = ((Object)physGrabObject).GetInstanceID();
				if (!HeldGunStates.TryGetValue(instanceID, out HeldGunState value))
				{
					value = new HeldGunState();
					HeldGunStates[instanceID] = value;
				}
				if (!value.Initialized)
				{
					value.BubbleTank = Plugin.TankCapacity.Value;
					value.Battery = FindBattery(((Component)physGrabObject).gameObject);
					SetBattery(value);
					value.Initialized = true;
				}
				BubbleGunNetworkProxy networkProxy = EnsureNetworkProxy(physGrabObject);
				SyncTankFromBattery(value);
				if (!IsHeldByLocalPlayer(physGrabObject))
				{
					UpdateSprayState(value, firing: false, null, null, null);
					SetBattery(value);
					return;
				}
				bool firing;
				bool num = TryGetItemUseHeld(physGrabObject, out firing) && firing;
				bool flag = Time.time < value.FireRequestedUntil;
				bool firing2 = num || flag;
				Transform val2 = FindDeep(((Component)physGrabObject).transform, "BubbleGun Barrel Origin") ?? ((Component)physGrabObject).transform;
				Transform aim = (((Object)(object)PlayerController.instance != (Object)null && (Object)(object)PlayerController.instance.cameraGameObject != (Object)null) ? PlayerController.instance.cameraGameObject.transform : val2);
				UpdateSprayState(value, firing2, val2, aim, networkProxy);
				SetBattery(value);
			}
		}

		private void Start()
		{
			playerController = ((Component)this).GetComponent<PlayerController>();
			if ((Object)(object)playerController != (Object)null)
			{
				BubbleTank = Plugin.TankCapacity.Value;
				Debug.Log((object)$"[BubbleGun] Controller attached to {((Object)playerController).name}. Tank={BubbleTank:0.0}");
			}
		}

		private void Update()
		{
		}

		private bool IsLocalController()
		{
			if ((Object)(object)playerController == (Object)null || !Object.op_Implicit((Object)(object)playerController))
			{
				return false;
			}
			if ((Object)(object)PlayerController.instance != (Object)null && (Object)(object)PlayerController.instance != (Object)(object)playerController)
			{
				return false;
			}
			PlayerAvatar playerAvatarScript = playerController.playerAvatarScript;
			if ((Object)(object)playerAvatarScript == (Object)null || !Object.op_Implicit((Object)(object)playerAvatarScript))
			{
				return (Object)(object)PlayerController.instance == (Object)(object)playerController;
			}
			object obj = PlayerAvatarIsLocalField?.GetValue(playerAvatarScript);
			if (obj is bool)
			{
				return (bool)obj;
			}
			return (Object)(object)PlayerController.instance == (Object)(object)playerController;
		}

		private bool TryGetFireHeld(out bool firing)
		{
			try
			{
				firing = SemiFunc.InputHold((InputKey)2);
				return true;
			}
			catch (Exception ex)
			{
				firing = false;
				if (!inputUnavailableLogged)
				{
					inputUnavailableLogged = true;
					Debug.LogWarning((object)("[BubbleGun] Fire input is unavailable; Bubble firing is disabled for this player controller. " + ex.GetType().Name + ": " + ex.Message));
				}
				return false;
			}
		}

		private static bool TryGetItemUseHeld(PhysGrabObject physGrabObject, out bool firing)
		{
			bool flag = false;
			try
			{
				flag = SemiFunc.InputHold((InputKey)2);
			}
			catch
			{
				flag = false;
			}
			ItemToggle val = ((Component)physGrabObject).GetComponent<ItemToggle>() ?? ((Component)physGrabObject).GetComponentInChildren<ItemToggle>(true) ?? ((Component)physGrabObject).GetComponentInParent<ItemToggle>();
			bool flag2 = default(bool);
			int num;
			if ((Object)(object)val != (Object)null)
			{
				object obj2 = ToggleImpulseField?.GetValue(val);
				if (obj2 is bool)
				{
					flag2 = (bool)obj2;
					num = 1;
				}
				else
				{
					num = 0;
				}
			}
			else
			{
				num = 0;
			}
			bool flag3 = (byte)((uint)num & (flag2 ? 1u : 0u)) != 0;
			firing = flag || ((Object)(object)val != (Object)null && (val.toggleState || flag3));
			return true;
		}

		private static bool IsHeldByLocalPlayer(PhysGrabObject physGrabObject)
		{
			object obj = HeldByLocalPlayerField?.GetValue(physGrabObject);
			if (obj is bool)
			{
				return (bool)obj;
			}
			PhysGrabber instance = PhysGrabber.instance;
			if ((Object)(object)instance == (Object)null || !Object.op_Implicit((Object)(object)instance))
			{
				return false;
			}
			object? obj2 = GrabbedPhysGrabObjectField?.GetValue(instance);
			PhysGrabObject val = (PhysGrabObject)((obj2 is PhysGrabObject) ? obj2 : null);
			if ((Object)(object)val != (Object)null)
			{
				return (Object)(object)val == (Object)(object)physGrabObject;
			}
			return false;
		}

		private bool TryGetHeldBubbleGun(out Transform barrel, out Transform aim)
		{
			barrel = null;
			aim = null;
			PhysGrabber instance = PhysGrabber.instance;
			if ((Object)(object)instance == (Object)null || !Object.op_Implicit((Object)(object)instance))
			{
				return false;
			}
			object? obj = GrabbedPhysGrabObjectField?.GetValue(instance);
			PhysGrabObject val = (PhysGrabObject)((obj is PhysGrabObject) ? obj : null);
			if ((Object)(object)val == (Object)null || !Object.op_Implicit((Object)(object)val))
			{
				return false;
			}
			ItemAttributes val2 = ((Component)val).GetComponent<ItemAttributes>() ?? ((Component)val).GetComponentInChildren<ItemAttributes>(true) ?? ((Component)val).GetComponentInParent<ItemAttributes>();
			if ((Object)(object)val2 == (Object)null || (Object)(object)val2.item == (Object)null || val2.item.itemName != "Bubble Gun")
			{
				return false;
			}
			barrel = FindDeep(((Component)val).transform, "BubbleGun Barrel Origin") ?? ((Component)val).transform;
			aim = (Transform)(((Object)(object)playerController.cameraGameObject != (Object)null) ? ((object)playerController.cameraGameObject.transform) : ((object)barrel));
			return true;
		}

		private static void UpdateSprayState(HeldGunState state, bool firing, Transform? barrel, Transform? aim, BubbleGunNetworkProxy? networkProxy)
		{
			float num = ((firing && state.BubbleTank > 0f) ? 1f : 0f);
			float num2 = ((num > state.Pressure) ? 7.5f : 5.5f);
			state.Pressure = Mathf.MoveTowards(state.Pressure, num, num2 * Time.deltaTime);
			if (state.Pressure <= 0.02f || (Object)(object)barrel == (Object)null || (Object)(object)aim == (Object)null || state.BubbleTank <= 0f)
			{
				state.SprayAccumulator = 0f;
				return;
			}
			float num3 = Mathf.Min(Plugin.TankDrainRate.Value, 5f);
			state.BubbleTank = Mathf.Max(0f, state.BubbleTank - num3 * state.Pressure * Time.deltaTime);
			state.SprayAccumulator += Time.deltaTime * Mathf.Lerp(28f, 18f, state.Pressure);
			int num4 = Mathf.Min(2, Mathf.FloorToInt(state.SprayAccumulator));
			if (num4 > 0)
			{
				state.SprayAccumulator -= num4;
				for (int i = 0; i < num4; i++)
				{
					FireGlob(barrel, aim, state.Pressure, networkProxy);
				}
			}
		}

		private static void BroadcastRemoteSpray(HeldGunState state, bool firing, Transform barrel, Transform aim, BubbleGunNetworkProxy? networkProxy)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			if (firing && !(state.Pressure <= 0.05f) && !((Object)(object)networkProxy == (Object)null) && !(Time.time < state.NextNetworkSprayAt))
			{
				state.NextNetworkSprayAt = Time.time + 0.06f;
				networkProxy.BroadcastSpray(barrel.position, aim.forward, state.Pressure);
			}
		}

		private static BubbleGunNetworkProxy? EnsureNetworkProxy(PhysGrabObject physGrabObject)
		{
			PhotonView val = ((Component)physGrabObject).GetComponent<PhotonView>() ?? ((Component)physGrabObject).GetComponentInChildren<PhotonView>(true) ?? ((Component)physGrabObject).GetComponentInParent<PhotonView>();
			if ((Object)(object)val == (Object)null || !Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			BubbleGunNetworkProxy bubbleGunNetworkProxy = ((Component)val).GetComponent<BubbleGunNetworkProxy>();
			if ((Object)(object)bubbleGunNetworkProxy == (Object)null || !Object.op_Implicit((Object)(object)bubbleGunNetworkProxy))
			{
				bubbleGunNetworkProxy = ((Component)val).gameObject.AddComponent<BubbleGunNetworkProxy>();
			}
			bubbleGunNetworkProxy.SetPhotonView(val);
			return bubbleGunNetworkProxy;
		}

		private static Component? FindBattery(GameObject root)
		{
			Component[] componentsInChildren = root.GetComponentsInChildren<Component>(true);
			foreach (Component val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && ((object)val).GetType().Name == "ItemBattery")
				{
					TrySetBatteryActive(val, active: true);
					return val;
				}
			}
			return null;
		}

		private static void SetBattery(HeldGunState state)
		{
			if (!((Object)(object)state.Battery == (Object)null) && Object.op_Implicit((Object)(object)state.Battery))
			{
				FieldInfo batteryLifeField = GetBatteryLifeField(state.Battery);
				if (batteryLifeField != null)
				{
					batteryLifeField.SetValue(state.Battery, Mathf.Clamp(state.BubbleTank, 0f, Plugin.TankCapacity.Value));
				}
				TrySetBatteryActive(state.Battery, active: true);
			}
		}

		private static void SyncTankFromBattery(HeldGunState state)
		{
			if (!((Object)(object)state.Battery == (Object)null) && Object.op_Implicit((Object)(object)state.Battery))
			{
				if (GetBatteryLifeField(state.Battery)?.GetValue(state.Battery) is float num && num > state.BubbleTank)
				{
					state.BubbleTank = Mathf.Clamp(num, 0f, Plugin.TankCapacity.Value);
				}
				TrySetBatteryActive(state.Battery, active: true);
			}
		}

		private static FieldInfo? GetBatteryLifeField(Component battery)
		{
			Type type = ((object)battery).GetType();
			if (!BatteryLifeFields.TryGetValue(type, out FieldInfo value))
			{
				value = type.GetField("batteryLife", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				BatteryLifeFields[type] = value;
			}
			return value;
		}

		private static void TrySetBatteryActive(Component battery, bool active)
		{
			Type type = ((object)battery).GetType();
			if (!BatteryActiveFields.TryGetValue(type, out FieldInfo value))
			{
				value = type.GetField("batteryActive", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				BatteryActiveFields[type] = value;
			}
			value?.SetValue(battery, active);
		}

		private static void FireSprayBurst(Transform barrel, Transform aim, float pressure = 1f)
		{
			for (int i = 0; i < 2; i++)
			{
				FireGlob(barrel, aim, pressure, null);
			}
		}

		private static void FireGlob(Transform barrel, Transform aim, float pressure, BubbleGunNetworkProxy? networkProxy)
		{
			//IL_0001: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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_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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: 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_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = barrel.right * Random.Range(-0.024f, 0.024f);
			Vector3 val2 = barrel.up * Random.Range(-0.02f, 0.02f);
			Vector3 position = barrel.position + val + val2 + aim.forward * 0.18f;
			PhysGrabObject componentInParent = ((Component)barrel).GetComponentInParent<PhysGrabObject>();
			Transform ignoredRoot = ((componentInParent != null) ? ((Component)componentInParent).transform : null);
			GameObject val3 = CreateGlobObject(position);
			int bubbleId = networkProxy?.CreateBubbleId() ?? ((Object)val3).GetInstanceID();
			Vector3 val4 = Quaternion.Euler(Random.Range(-5.5f, 5.5f), Random.Range(-5.5f, 5.5f), Random.Range(-2f, 2f)) * aim.forward;
			Rigidbody val5 = default(Rigidbody);
			if (val3.TryGetComponent<Rigidbody>(ref val5))
			{
				float num = Mathf.Max(Plugin.BubbleSpeed.Value, 2f);
				float num2 = Mathf.Lerp(num * 0.7f, num * 1.15f, pressure);
				float num3 = Random.Range(num2 * 0.82f, num2) * 0.9f;
				val5.velocity = ((Vector3)(ref val4)).normalized * num3 + Vector3.up * Random.Range(0.03f, 0.22f);
				networkProxy?.BroadcastBubbleLaunch(bubbleId, position, val5.velocity, val3.transform.localScale.x, 7f, Plugin.ArmedLifetime.Value);
			}
			val3.AddComponent<BubbleBomb>().Initialize(7f, Plugin.ArmedLifetime.Value, Plugin.ExplosionRadius.Value, Plugin.ChainReactionRadius.Value, Plugin.ExplosionDamage.Value, Plugin.ExplosionKnockback.Value, networkProxy, bubbleId, ignoredRoot);
		}

		internal static void SpawnRemoteVisualSpray(Vector3 barrelPosition, Vector3 aimForward, float pressure, int seed)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: 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_009c: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			State state = Random.state;
			Random.InitState(seed);
			try
			{
				int num = Mathf.Clamp(Mathf.RoundToInt(Mathf.Lerp(5f, 11f, pressure)), 5, 11);
				Vector3 val = ((((Vector3)(ref aimForward)).sqrMagnitude > 0.01f) ? ((Vector3)(ref aimForward)).normalized : Vector3.forward);
				Rigidbody val3 = default(Rigidbody);
				for (int i = 0; i < num; i++)
				{
					GameObject obj = CreateGlobObject(barrelPosition);
					Transform transform = obj.transform;
					transform.localScale *= 1.45f;
					Vector3 val2 = Quaternion.Euler(Random.Range(-5.5f, 5.5f), Random.Range(-5.5f, 5.5f), Random.Range(-2f, 2f)) * val;
					if (obj.TryGetComponent<Rigidbody>(ref val3))
					{
						float num2 = Mathf.Max(Plugin.BubbleSpeed.Value, 2f);
						float num3 = Mathf.Lerp(num2 * 0.7f, num2 * 1.15f, pressure);
						val3.velocity = ((Vector3)(ref val2)).normalized * Random.Range(num3 * 0.82f, num3) * 0.9f;
					}
					obj.AddComponent<BubbleVisualBubble>().Initialize(7f);
				}
			}
			finally
			{
				Random.state = state;
			}
		}

		internal static void SpawnRemoteVisualBubble(int bubbleId, Vector3 position, Vector3 velocity, float scale, float flightLifetime, float armedLifetime, int seed)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			State state = Random.state;
			Random.InitState(seed);
			try
			{
				GameObject obj = CreateGlobObject(position);
				obj.transform.localScale = Vector3.one * Mathf.Clamp(scale, 0.08f, 0.45f);
				Rigidbody val = default(Rigidbody);
				if (obj.TryGetComponent<Rigidbody>(ref val))
				{
					val.velocity = velocity;
				}
				obj.AddComponent<BubbleRemoteVisualBubble>().Initialize(bubbleId, flightLifetime, armedLifetime);
			}
			finally
			{
				Random.state = state;
			}
		}

		private static GameObject CreateGlobObject(Vector3 position)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = GameObject.CreatePrimitive((PrimitiveType)0);
			((Object)obj).name = "BubbleBomb";
			obj.transform.position = position;
			float num = Random.Range(0.16f, 0.26f);
			obj.transform.localScale = Vector3.one * num;
			Collider val = default(Collider);
			if (obj.TryGetComponent<Collider>(ref val))
			{
				val.isTrigger = true;
			}
			Rigidbody obj2 = obj.AddComponent<Rigidbody>();
			obj2.collisionDetectionMode = (CollisionDetectionMode)2;
			obj2.useGravity = false;
			obj2.drag = 0.24f;
			obj2.angularDrag = 0.15f;
			Renderer val2 = default(Renderer);
			if (obj.TryGetComponent<Renderer>(ref val2))
			{
				val2.material = GetOrCreateBubbleMaterial();
			}
			return obj;
		}

		private static Material GetOrCreateBubbleMaterial()
		{
			if ((Object)(object)_BubbleMaterial != (Object)null && Object.op_Implicit((Object)(object)_BubbleMaterial))
			{
				return _BubbleMaterial;
			}
			_BubbleMaterial = CreateBubbleMaterial();
			return _BubbleMaterial;
		}

		private static Material CreateBubbleMaterial()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_0036: 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)
			GameObject val = GameObject.CreatePrimitive((PrimitiveType)0);
			Material val2;
			try
			{
				val2 = new Material(val.GetComponent<Renderer>().sharedMaterial);
			}
			finally
			{
				Object.Destroy((Object)(object)val);
			}
			val2.color = new Color(0.78f, 0.92f, 1f, 0.34f);
			TrySetTransparent(val2);
			if (val2.HasProperty("_EmissionColor"))
			{
				val2.EnableKeyword("_EMISSION");
				val2.SetColor("_EmissionColor", new Color(0.25f, 0.42f, 0.9f, 0.45f));
			}
			return val2;
		}

		private static void TrySetTransparent(Material mat)
		{
			try
			{
				mat.SetFloat("_Mode", 3f);
				mat.SetInt("_SrcBlend", 5);
				mat.SetInt("_DstBlend", 10);
				mat.SetInt("_ZWrite", 0);
				mat.DisableKeyword("_ALPHATEST_ON");
				mat.EnableKeyword("_ALPHABLEND_ON");
				mat.DisableKeyword("_ALPHAPREMULTIPLY_ON");
				mat.renderQueue = 3000;
			}
			catch
			{
			}
			try
			{
				mat.SetFloat("_Surface", 1f);
				mat.SetFloat("_Blend", 0f);
				mat.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");
			}
			catch
			{
			}
		}

		private static Transform? FindDeep(Transform root, string name)
		{
			Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if (((Object)val).name == name)
				{
					return val;
				}
			}
			return null;
		}
	}
	public sealed class BubbleGunNetworkProxy : MonoBehaviour
	{
		private PhotonView? photonView;

		private int packetCounter;

		private int bubbleCounter;

		internal void SetPhotonView(PhotonView view)
		{
			photonView = view;
		}

		internal void BroadcastSpray(Vector3 barrelPosition, Vector3 aimForward, float pressure)
		{
			//IL_006c: 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)
			if (SemiFunc.IsMultiplayer() && !((Object)(object)photonView == (Object)null) && Object.op_Implicit((Object)(object)photonView))
			{
				int num = (photonView.ViewID * 397) ^ packetCounter++ ^ Mathf.RoundToInt(Time.time * 1000f);
				photonView.RPC("RemoteSprayRPC", (RpcTarget)1, new object[4] { barrelPosition, aimForward, pressure, num });
			}
		}

		internal int CreateBubbleId()
		{
			return ((((Object)(object)photonView != (Object)null && Object.op_Implicit((Object)(object)photonView)) ? photonView.ViewID : ((Object)this).GetInstanceID()) * 397) ^ ++bubbleCounter ^ Mathf.RoundToInt(Time.time * 1000f);
		}

		internal void BroadcastBubbleLaunch(int bubbleId, Vector3 position, Vector3 velocity, float scale, float flightLifetime, float armedLifetime)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.IsMultiplayer() && !((Object)(object)photonView == (Object)null) && Object.op_Implicit((Object)(object)photonView))
			{
				int num = (photonView.ViewID * 397) ^ packetCounter++ ^ Mathf.RoundToInt(Time.time * 1000f);
				photonView.RPC("RemoteBubbleLaunchRPC", (RpcTarget)1, new object[7] { bubbleId, position, velocity, scale, flightLifetime, armedLifetime, num });
			}
		}

		internal void BroadcastBubblePop(int bubbleId, Vector3 position, float radius, bool chainTriggered)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.IsMultiplayer() && !((Object)(object)photonView == (Object)null) && Object.op_Implicit((Object)(object)photonView))
			{
				photonView.RPC("RemoteBubblePopRPC", (RpcTarget)1, new object[4] { bubbleId, position, radius, chainTriggered });
			}
		}

		internal void RequestExplosionDamage(Vector3 position, float radius, int damage, float knockback)
		{
			//IL_000e: 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)
			if (!SemiFunc.IsMultiplayer() || SemiFunc.IsMasterClientOrSingleplayer())
			{
				ApplyExplosionDamageAsMaster(position, radius, damage, knockback);
			}
			else if (!((Object)(object)photonView == (Object)null) && Object.op_Implicit((Object)(object)photonView))
			{
				photonView.RPC("RequestExplosionDamageRPC", (RpcTarget)2, new object[4] { position, radius, damage, knockback });
			}
		}

		[PunRPC]
		private void RemoteSprayRPC(Vector3 barrelPosition, Vector3 aimForward, float pressure, int seed)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (BubbleGunRuntime.Enabled)
			{
				BubbleGunController.SpawnRemoteVisualSpray(barrelPosition, aimForward, Mathf.Clamp01(pressure), seed);
			}
		}

		[PunRPC]
		private void RemoteBubbleLaunchRPC(int bubbleId, Vector3 position, Vector3 velocity, float scale, float flightLifetime, float armedLifetime, int seed)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if (BubbleGunRuntime.Enabled)
			{
				BubbleGunController.SpawnRemoteVisualBubble(bubbleId, position, velocity, scale, flightLifetime, armedLifetime, seed);
			}
		}

		[PunRPC]
		private void RemoteBubblePopRPC(int bubbleId, Vector3 position, float radius, bool chainTriggered)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (BubbleGunRuntime.Enabled)
			{
				BubbleRemoteVisualBubble.PopFromNetwork(bubbleId, position, radius, chainTriggered);
			}
		}

		[PunRPC]
		private void RequestExplosionDamageRPC(Vector3 position, float radius, int damage, float knockback)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (BubbleGunRuntime.Enabled && PhotonNetwork.IsMasterClient)
			{
				ApplyExplosionDamageAsMaster(position, radius, damage, knockback);
			}
		}

		internal static void SpawnPopVfx(Vector3 position, float radius, bool chainTriggered)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = GameObject.CreatePrimitive((PrimitiveType)0);
			((Object)obj).name = (chainTriggered ? "BubbleChainPopRemoteVfx" : "BubblePopRemoteVfx");
			obj.transform.position = position;
			obj.transform.localScale = Vector3.one * 0.14f;
			Collider val = default(Collider);
			if (obj.TryGetComponent<Collider>(ref val))
			{
				Object.Destroy((Object)(object)val);
			}
			Material material = obj.GetComponent<Renderer>().material;
			material.color = new Color(0.78f, 0.95f, 1f, 0.38f);
			TrySetTransparent(material);
			float targetScale = (chainTriggered ? Mathf.Max(2.8f, radius * 1.45f) : Mathf.Max(0.5f, radius));
			float lifetime = (chainTriggered ? 0.42f : 0.24f);
			obj.AddComponent<BubblePopVfx>().Initialize(lifetime, targetScale);
		}

		private static void ApplyExplosionDamageAsMaster(Vector3 position, float radius, int damage, float knockback)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			HashSet<int> hashSet = new HashSet<int>();
			Collider[] array = Physics.OverlapSphere(position, Mathf.Clamp(radius, 0.5f, 8f), -1, (QueryTriggerInteraction)2);
			foreach (Collider val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Enemy val2 = BubbleCombat.FindEnemy(val);
				if (!((Object)(object)val2 == (Object)null) && Object.op_Implicit((Object)(object)val2) && hashSet.Add(((Object)val2).GetInstanceID()))
				{
					BubbleCombat.DamageEnemy(val2, Mathf.Clamp(damage, 0, 24), position);
					Rigidbody enemyRigidbody = BubbleCombat.GetEnemyRigidbody(val2);
					if ((Object)(object)enemyRigidbody != (Object)null && Object.op_Implicit((Object)(object)enemyRigidbody))
					{
						enemyRigidbody.AddExplosionForce(Mathf.Clamp(knockback, 0f, 80f), position, radius, 0.45f, (ForceMode)1);
					}
				}
			}
		}

		private static void TrySetTransparent(Material mat)
		{
			try
			{
				mat.SetFloat("_Mode", 3f);
				mat.SetInt("_SrcBlend", 5);
				mat.SetInt("_DstBlend", 10);
				mat.SetInt("_ZWrite", 0);
				mat.DisableKeyword("_ALPHATEST_ON");
				mat.EnableKeyword("_ALPHABLEND_ON");
				mat.DisableKeyword("_ALPHAPREMULTIPLY_ON");
				mat.renderQueue = 3000;
			}
			catch
			{
			}
			try
			{
				mat.SetFloat("_Surface", 1f);
				mat.SetFloat("_Blend", 0f);
				mat.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");
			}
			catch
			{
			}
		}
	}
	internal static class BubbleGunRuntime
	{
		internal static bool Enabled { get; set; } = true;


		internal static string PluginDirectory { get; set; } = string.Empty;

	}
	public sealed class BubbleVisualBubble : MonoBehaviour
	{
		private Material? material;

		private Vector3 baseScale;

		private float expiresAt;

		private float hueOffset;

		internal void Initialize(float lifetime)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			expiresAt = Time.time + lifetime;
			baseScale = ((Component)this).transform.localScale;
			hueOffset = Random.value;
			Renderer component = ((Component)this).GetComponent<Renderer>();
			material = ((component != null) ? component.material : null);
		}

		private void Update()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: 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_008e: 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_00c4: 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)
			if (Time.time >= expiresAt)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			float num = 1f + Mathf.Sin(Time.time * 2.1f + hueOffset) * 0.018f;
			((Component)this).transform.localScale = baseScale * num;
			if (!((Object)(object)material == (Object)null))
			{
				Color val = Color.HSVToRGB(Mathf.Repeat(hueOffset + Time.time * 0.12f, 1f), 0.55f, 1f);
				val.a = 0.28f;
				material.color = val;
				if (material.HasProperty("_EmissionColor"))
				{
					material.SetColor("_EmissionColor", val * 0.32f);
				}
			}
		}
	}
	public sealed class BubblePopVfx : MonoBehaviour
	{
		private Material? material;

		private Vector3 startScale;

		private float startTime;

		private float lifetime;

		private float targetScale;

		internal void Initialize(float lifetime, float targetScale)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			this.lifetime = Mathf.Max(0.05f, lifetime);
			this.targetScale = Mathf.Max(0.1f, targetScale);
			startTime = Time.time;
			startScale = ((Component)this).transform.localScale;
			Renderer component = ((Component)this).GetComponent<Renderer>();
			material = ((component != null) ? component.material : null);
		}

		private void Update()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Clamp01((Time.time - startTime) / lifetime);
			((Component)this).transform.localScale = Vector3.Lerp(startScale, Vector3.one * targetScale, num);
			if ((Object)(object)material != (Object)null)
			{
				Color color = Color.HSVToRGB(Mathf.Repeat(Time.time * 0.8f, 1f), 0.48f, 1f);
				color.a = Mathf.Lerp(0.42f, 0f, num);
				material.color = color;
			}
			if (num >= 1f)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}
	public sealed class BubbleRemoteVisualBubble : MonoBehaviour
	{
		private enum VisualState
		{
			Floating,
			Armed,
			Popped
		}

		private static readonly Dictionary<int, BubbleRemoteVisualBubble> RemoteBubbles = new Dictionary<int, BubbleRemoteVisualBubble>();

		private VisualState state;

		private Rigidbody? rb;

		private Material? material;

		private Vector3 baseScale;

		private int bubbleId;

		private float spawnTime;

		private float expiresAt;

		private float armedLifetime;

		private float hueOffset;

		private const float ContactGraceSeconds = 0.16f;

		private const float ContactRadius = 0.14f;

		private const float BubbleWeight = 0.11f;

		private const float VerticalBob = 0.06f;

		private const float SideDrift = 0.055f;

		internal void Initialize(int bubbleId, float flightLifetime, float armedLifetime)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			this.bubbleId = bubbleId;
			spawnTime = Time.time;
			expiresAt = Time.time + Mathf.Max(0.25f, flightLifetime);
			this.armedLifetime = Mathf.Max(1f, armedLifetime);
			baseScale = ((Component)this).transform.localScale;
			hueOffset = Random.value;
			rb = ((Component)this).GetComponent<Rigidbody>();
			Renderer component = ((Component)this).GetComponent<Renderer>();
			material = ((component != null) ? component.material : null);
			RemoteBubbles[bubbleId] = this;
		}

		private void OnDestroy()
		{
			if (RemoteBubbles.TryGetValue(bubbleId, out BubbleRemoteVisualBubble value) && (Object)(object)value == (Object)(object)this)
			{
				RemoteBubbles.Remove(bubbleId);
			}
		}

		internal static void PopFromNetwork(int bubbleId, Vector3 position, float radius, bool chainTriggered)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (RemoteBubbles.TryGetValue(bubbleId, out BubbleRemoteVisualBubble value) && (Object)(object)value != (Object)null && Object.op_Implicit((Object)(object)value))
			{
				value.Pop(position, radius, chainTriggered);
			}
			else
			{
				BubbleGunNetworkProxy.SpawnPopVfx(position, radius, chainTriggered);
			}
		}

		private void Update()
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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_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)
			AnimateShell();
			if (state == VisualState.Floating && (Object)(object)rb != (Object)null)
			{
				float num = Mathf.Sin((Time.time + hueOffset) * 2.1f) * 0.055f;
				float num2 = Mathf.Sin((Time.time + hueOffset) * 3.4f) * 0.06f;
				rb.AddForce(Vector3.down * 0.11f + Vector3.up * num2 + ((Component)this).transform.right * num, (ForceMode)5);
				CheckContacts();
			}
			if (Time.time >= expiresAt)
			{
				if (state == VisualState.Armed)
				{
					expiresAt = Time.time + 5f;
				}
				else
				{
					Object.Destroy((Object)(object)((Component)this).gameObject);
				}
			}
		}

		private void OnTriggerEnter(Collider other)
		{
			if (state == VisualState.Floating)
			{
				HandleContact(other);
			}
		}

		private void CheckContacts()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time - spawnTime < 0.16f)
			{
				return;
			}
			Collider[] array = Physics.OverlapSphere(((Component)this).transform.position, 0.14f, -1, (QueryTriggerInteraction)2);
			foreach (Collider val in array)
			{
				if ((Object)(object)val != (Object)null && HandleContact(val))
				{
					break;
				}
			}
		}

		private bool HandleContact(Collider other)
		{
			if ((Object)(object)other == (Object)null || (Object)(object)((Component)other).transform == (Object)(object)((Component)this).transform || (Object)(object)((Component)other).GetComponentInParent<BubbleRemoteVisualBubble>() == (Object)(object)this)
			{
				return false;
			}
			if ((Object)(object)((Component)other).GetComponentInParent<PlayerAvatar>() != (Object)null || (Object)(object)((Component)other).GetComponentInParent<PlayerController>() != (Object)null || IsBubbleGunCollider(other))
			{
				return false;
			}
			if ((Object)(object)((Component)other).GetComponentInParent<Enemy>() != (Object)null || (Object)(object)((Component)other).GetComponentInParent<EnemyRigidbody>() != (Object)null)
			{
				return false;
			}
			if (other.isTrigger)
			{
				return false;
			}
			return ArmOnSurface(other);
		}

		private bool ArmOnSurface(Collider surface)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: 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_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			if (state != 0)
			{
				return false;
			}
			Vector3 val = surface.ClosestPoint(((Component)this).transform.position);
			Vector3 val2 = ((Component)this).transform.position - val;
			float magnitude = ((Vector3)(ref val2)).magnitude;
			float num = Mathf.Max(0.04f, ((Component)this).transform.lossyScale.x * 0.65f);
			if (magnitude < 0.02f || magnitude > num)
			{
				return false;
			}
			state = VisualState.Armed;
			expiresAt = Time.time + armedLifetime;
			Vector3 val3 = val2 / magnitude;
			((Component)this).transform.position = val + val3 * Mathf.Max(0.025f, ((Component)this).transform.lossyScale.x * 0.32f);
			if ((Object)(object)rb != (Object)null)
			{
				rb.velocity = Vector3.zero;
				rb.angularVelocity = Vector3.zero;
				rb.isKinematic = true;
			}
			return true;
		}

		private static bool IsBubbleGunCollider(Collider other)
		{
			ItemAttributes componentInParent = ((Component)other).GetComponentInParent<ItemAttributes>();
			if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.item != (Object)null)
			{
				return componentInParent.item.itemName == "Bubble Gun";
			}
			return false;
		}

		private void Pop(Vector3 position, float radius, bool chainTriggered)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if (state != VisualState.Popped)
			{
				state = VisualState.Popped;
				BubbleGunNetworkProxy.SpawnPopVfx(position, radius, chainTriggered);
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}

		private void AnimateShell()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)material == (Object)null))
			{
				Color val = Color.HSVToRGB(Mathf.Repeat(hueOffset + Time.time * 0.12f, 1f), 0.55f, 1f);
				val.a = ((state == VisualState.Armed) ? 0.46f : 0.3f);
				material.color = val;
				if (material.HasProperty("_EmissionColor"))
				{
					material.SetColor("_EmissionColor", val * ((state == VisualState.Armed) ? 0.5f : 0.3f));
				}
				float num = ((state == VisualState.Armed) ? (1f + Mathf.Sin(Time.time * 8f) * 0.035f) : (1f + Mathf.Sin(Time.time * 2.2f + hueOffset) * 0.018f));
				((Component)this).transform.localScale = baseScale * num;
			}
		}
	}
}