Decompiled source of LightBat v1.0.8

LightBat.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LethalConfig;
using LethalConfig.ConfigItems;
using LethalConfig.ConfigItems.Options;
using LethalLib.Modules;
using LightBat.NetcodePatcher;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Events;
using UnityEngine.Rendering;

[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("LightBat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.5.14.0")]
[assembly: AssemblyInformationalVersion("1.5.14+32232b3d8fbc21fec22ae47f05d6c6ce11c65438")]
[assembly: AssemblyProduct("LightBat")]
[assembly: AssemblyTitle("LightBat")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.5.14.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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]
	[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 LightBat
{
	internal static class DepletedApparatusRegistry
	{
		private static readonly int EmissiveColorProperty = Shader.PropertyToID("_EmissiveColor");

		private static readonly int EmissiveColorLdrProperty = Shader.PropertyToID("_EmissiveColorLDR");

		private static readonly int EmissiveIntensityProperty = Shader.PropertyToID("_EmissiveIntensity");

		private static readonly int StandardEmissionColorProperty = Shader.PropertyToID("_EmissionColor");

		private static readonly Dictionary<ulong, DepletedApparatusState> ActiveStates = new Dictionary<ulong, DepletedApparatusState>();

		private static GameObject? StatePrefab { get; set; }

		internal static bool Register(AssetBundle assets)
		{
			if ((Object)(object)StatePrefab != (Object)null)
			{
				return true;
			}
			GameObject val = assets.LoadAsset<GameObject>("DepletedApparatusState");
			if ((Object)(object)val == (Object)null || (Object)(object)val.GetComponent<NetworkObject>() == (Object)null || (Object)(object)val.GetComponent<DepletedApparatusState>() == (Object)null)
			{
				Plugin.Logger.LogError((object)"The asset bundle is missing the depleted Apparatus network state prefab.");
				return false;
			}
			NetworkPrefabs.RegisterNetworkPrefab(val);
			StatePrefab = val;
			Plugin.Logger.LogInfo((object)"Registered the persistent depleted Apparatus network state.");
			return true;
		}

		internal static bool SpawnState(LungProp apparatus, int scrapValue)
		{
			//IL_0084: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
			NetworkObject val = default(NetworkObject);
			if ((Object)(object)apparatus == (Object)null || (Object)(object)StatePrefab == (Object)null || (Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsServer || !((Component)apparatus).TryGetComponent<NetworkObject>(ref val) || !val.IsSpawned)
			{
				return false;
			}
			ulong networkObjectId = val.NetworkObjectId;
			if (ActiveStates.TryGetValue(networkObjectId, out DepletedApparatusState value) && (Object)(object)value != (Object)null && ((NetworkBehaviour)value).IsSpawned)
			{
				ApplyState(apparatus, scrapValue);
				return true;
			}
			ActiveStates.Remove(networkObjectId);
			GameObject val2 = Object.Instantiate<GameObject>(StatePrefab, Vector3.zero, Quaternion.identity);
			NetworkObject component = val2.GetComponent<NetworkObject>();
			DepletedApparatusState component2 = val2.GetComponent<DepletedApparatusState>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null)
			{
				Object.Destroy((Object)(object)val2);
				return false;
			}
			component.Spawn(false);
			ActiveStates[networkObjectId] = component2;
			component2.Initialize(new NetworkObjectReference(val), scrapValue);
			return true;
		}

		internal static void UnregisterState(DepletedApparatusState state)
		{
			ulong? num = null;
			foreach (KeyValuePair<ulong, DepletedApparatusState> activeState in ActiveStates)
			{
				if ((Object)(object)activeState.Value == (Object)(object)state)
				{
					num = activeState.Key;
					break;
				}
			}
			if (num.HasValue)
			{
				ActiveStates.Remove(num.Value);
			}
		}

		internal static void ApplyState(LungProp apparatus, int scrapValue)
		{
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			//IL_0104: 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_0124: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)apparatus == (Object)null)
			{
				return;
			}
			apparatus.isLungPowered = false;
			((GrabbableObject)apparatus).isBeingUsed = false;
			apparatus.lungDeviceLightIntensity = 0f;
			((GrabbableObject)apparatus).SetScrapValue(Mathf.Max(0, scrapValue));
			Light[] componentsInChildren = ((Component)apparatus).GetComponentsInChildren<Light>(true);
			foreach (Light val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null))
				{
					val.intensity = 0f;
					((Behaviour)val).enabled = false;
				}
			}
			ParticleSystem[] componentsInChildren2 = ((Component)apparatus).GetComponentsInChildren<ParticleSystem>(true);
			foreach (ParticleSystem val2 in componentsInChildren2)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					val2.Stop(true, (ParticleSystemStopBehavior)0);
				}
			}
			if ((Object)(object)apparatus.sparkParticle != (Object)null)
			{
				apparatus.sparkParticle.SetActive(false);
			}
			MaterialPropertyBlock val3 = new MaterialPropertyBlock();
			Renderer[] componentsInChildren3 = ((Component)apparatus).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val4 in componentsInChildren3)
			{
				if (!((Object)(object)val4 == (Object)null) && !((Object)((Component)val4).transform).name.StartsWith("ScanNode", StringComparison.OrdinalIgnoreCase))
				{
					val4.GetPropertyBlock(val3);
					val3.SetColor(EmissiveColorProperty, Color.black);
					val3.SetColor(EmissiveColorLdrProperty, Color.black);
					val3.SetColor(StandardEmissionColorProperty, Color.black);
					val3.SetFloat(EmissiveIntensityProperty, 0f);
					val4.SetPropertyBlock(val3);
					val3.Clear();
				}
			}
		}
	}
	public sealed class DepletedApparatusState : NetworkBehaviour
	{
		private const float ResolveTimeout = 15f;

		private const float MissingTargetDespawnDelay = 5f;

		private const float StateEnforcementInterval = 0.75f;

		private readonly NetworkVariable<NetworkObjectReference> targetApparatus = new NetworkVariable<NetworkObjectReference>(default(NetworkObjectReference), (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<bool> initialized = new NetworkVariable<bool>(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		internal readonly NetworkVariable<int> finalScrapValue = new NetworkVariable<int>(30, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private Coroutine? resolveCoroutine;

		private float missingTargetTime;

		private float nextStateEnforcementTime;

		internal void Initialize(NetworkObjectReference apparatusReference, int finalScrapValue)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (!((NetworkBehaviour)this).IsServer || !((NetworkBehaviour)this).IsSpawned)
			{
				Plugin.Logger.LogError((object)"Tried to initialize a depleted Apparatus state before its network object was spawned.");
				return;
			}
			targetApparatus.Value = apparatusReference;
			this.finalScrapValue.Value = finalScrapValue;
			initialized.Value = true;
			StartResolvingTarget();
		}

		public override void OnNetworkSpawn()
		{
			((NetworkBehaviour)this).OnNetworkSpawn();
			NetworkVariable<NetworkObjectReference> obj = targetApparatus;
			obj.OnValueChanged = (OnValueChangedDelegate<NetworkObjectReference>)(object)Delegate.Combine((Delegate?)(object)obj.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<NetworkObjectReference>(OnTargetChanged));
			NetworkVariable<bool> obj2 = initialized;
			obj2.OnValueChanged = (OnValueChangedDelegate<bool>)(object)Delegate.Combine((Delegate?)(object)obj2.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<bool>(OnInitializedChanged));
			if (initialized.Value)
			{
				StartResolvingTarget();
			}
		}

		public override void OnNetworkDespawn()
		{
			DepletedApparatusRegistry.UnregisterState(this);
			NetworkVariable<NetworkObjectReference> obj = targetApparatus;
			obj.OnValueChanged = (OnValueChangedDelegate<NetworkObjectReference>)(object)Delegate.Remove((Delegate?)(object)obj.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<NetworkObjectReference>(OnTargetChanged));
			NetworkVariable<bool> obj2 = initialized;
			obj2.OnValueChanged = (OnValueChangedDelegate<bool>)(object)Delegate.Remove((Delegate?)(object)obj2.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<bool>(OnInitializedChanged));
			if (resolveCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(resolveCoroutine);
				resolveCoroutine = null;
			}
			((NetworkBehaviour)this).OnNetworkDespawn();
		}

		private void Update()
		{
			//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)
			if (!((NetworkBehaviour)this).IsSpawned || !initialized.Value)
			{
				return;
			}
			NetworkObjectReference value = targetApparatus.Value;
			NetworkObject val = default(NetworkObject);
			LungProp apparatus = default(LungProp);
			if (((NetworkObjectReference)(ref value)).TryGet(ref val, (NetworkManager)null) && ((Component)val).TryGetComponent<LungProp>(ref apparatus))
			{
				missingTargetTime = 0f;
				if (Time.time >= nextStateEnforcementTime)
				{
					DepletedApparatusRegistry.ApplyState(apparatus, finalScrapValue.Value);
					nextStateEnforcementTime = Time.time + 0.75f;
				}
			}
			else if (((NetworkBehaviour)this).IsServer)
			{
				missingTargetTime += Time.deltaTime;
				if (missingTargetTime >= 5f)
				{
					((NetworkBehaviour)this).NetworkObject.Despawn(true);
				}
			}
		}

		private void OnTargetChanged(NetworkObjectReference previous, NetworkObjectReference current)
		{
			if (initialized.Value)
			{
				StartResolvingTarget();
			}
		}

		private void OnInitializedChanged(bool previous, bool current)
		{
			if (current)
			{
				StartResolvingTarget();
			}
		}

		private void StartResolvingTarget()
		{
			if (((NetworkBehaviour)this).IsSpawned && !TryApplyState())
			{
				if (resolveCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(resolveCoroutine);
				}
				resolveCoroutine = ((MonoBehaviour)this).StartCoroutine(ResolveTarget());
			}
		}

		private IEnumerator ResolveTarget()
		{
			float startedAt = Time.realtimeSinceStartup;
			while (((NetworkBehaviour)this).IsSpawned && initialized.Value && Time.realtimeSinceStartup - startedAt < 15f)
			{
				if (TryApplyState())
				{
					resolveCoroutine = null;
					yield break;
				}
				yield return null;
			}
			resolveCoroutine = null;
			if (((NetworkBehaviour)this).IsSpawned && initialized.Value)
			{
				Plugin.Logger.LogWarning((object)"Could not resolve the Apparatus for a replicated depleted Apparatus state.");
			}
		}

		private bool TryApplyState()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (initialized.Value)
			{
				NetworkObjectReference value = targetApparatus.Value;
				NetworkObject val = default(NetworkObject);
				LungProp apparatus = default(LungProp);
				if (((NetworkObjectReference)(ref value)).TryGet(ref val, (NetworkManager)null) && ((Component)val).TryGetComponent<LungProp>(ref apparatus))
				{
					DepletedApparatusRegistry.ApplyState(apparatus, finalScrapValue.Value);
					nextStateEnforcementTime = Time.time + 0.75f;
					return true;
				}
			}
			return false;
		}

		protected override void __initializeVariables()
		{
			if (targetApparatus == null)
			{
				throw new Exception("DepletedApparatusState.targetApparatus cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			((NetworkVariableBase)targetApparatus).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)targetApparatus, "targetApparatus");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)targetApparatus);
			if (initialized == null)
			{
				throw new Exception("DepletedApparatusState.initialized cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			((NetworkVariableBase)initialized).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)initialized, "initialized");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)initialized);
			if (finalScrapValue == null)
			{
				throw new Exception("DepletedApparatusState.finalScrapValue cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			((NetworkVariableBase)finalScrapValue).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)finalScrapValue, "finalScrapValue");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)finalScrapValue);
			((NetworkBehaviour)this).__initializeVariables();
		}

		protected override void __initializeRpcs()
		{
			((NetworkBehaviour)this).__initializeRpcs();
		}

		protected internal override string __getTypeName()
		{
			return "DepletedApparatusState";
		}
	}
	internal static class DischargedLampRegistry
	{
		private static readonly int EmissiveColorProperty = Shader.PropertyToID("_EmissiveColor");

		private static readonly int EmissiveColorLdrProperty = Shader.PropertyToID("_EmissiveColorLDR");

		private static readonly int EmissiveIntensityProperty = Shader.PropertyToID("_EmissiveIntensity");

		private static readonly int StandardEmissionColorProperty = Shader.PropertyToID("_EmissionColor");

		private static readonly Vector3 SpawnedLampMeshCorrection = new Vector3(180f, 0f, 0f);

		private static Quaternion? authoredModelRotation;

		internal static Item? Item { get; private set; }

		private static GameObject? StatePrefab { get; set; }

		internal static bool Register(AssetBundle assets)
		{
			if ((Object)(object)Item != (Object)null)
			{
				return true;
			}
			Item val = assets.LoadAsset<Item>("DischargedLamp");
			GameObject val2 = assets.LoadAsset<GameObject>("DischargedLampState");
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Logger.LogError((object)"The asset bundle is missing the Discharged lamp Item.");
				return false;
			}
			if ((Object)(object)val2 == (Object)null || (Object)(object)val2.GetComponent<NetworkObject>() == (Object)null || (Object)(object)val2.GetComponent<DischargedLampState>() == (Object)null)
			{
				Plugin.Logger.LogError((object)"The asset bundle is missing the Discharged lamp network state prefab.");
				return false;
			}
			GameObject spawnPrefab = val.spawnPrefab;
			PhysicsProp val3 = (((Object)(object)spawnPrefab != (Object)null) ? spawnPrefab.GetComponent<PhysicsProp>() : null);
			if ((Object)(object)spawnPrefab == (Object)null || (Object)(object)spawnPrefab.GetComponent<NetworkObject>() == (Object)null || (Object)(object)val3 == (Object)null)
			{
				Plugin.Logger.LogError((object)"The Discharged lamp Item has an invalid network prefab.");
				return false;
			}
			((Object)val).name = "DischargedLamp";
			val.itemName = "Discharged lamp";
			((GrabbableObject)val3).itemProperties = val;
			NetworkPrefabs.RegisterNetworkPrefab(spawnPrefab);
			NetworkPrefabs.RegisterNetworkPrefab(val2);
			Items.RegisterItem(val);
			Item = val;
			StatePrefab = val2;
			Plugin.Logger.LogInfo((object)"Registered Discharged lamp as a non-spawning LethalLib item.");
			return true;
		}

		internal static bool SpawnState(GrabbableObject lamp, int scrapValue)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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)
			NetworkObject val = default(NetworkObject);
			if ((Object)(object)lamp == (Object)null || (Object)(object)StatePrefab == (Object)null || (Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsServer || !((Component)lamp).TryGetComponent<NetworkObject>(ref val) || !val.IsSpawned)
			{
				return false;
			}
			GameObject val2 = Object.Instantiate<GameObject>(StatePrefab, Vector3.zero, Quaternion.identity);
			NetworkObject component = val2.GetComponent<NetworkObject>();
			DischargedLampState component2 = val2.GetComponent<DischargedLampState>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null)
			{
				Object.Destroy((Object)(object)val2);
				return false;
			}
			component.Spawn(false);
			component2.Initialize(new NetworkObjectReference(val), scrapValue);
			return true;
		}

		internal static void ApplyState(GrabbableObject lamp, int scrapValue)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)lamp == (Object)null)
			{
				return;
			}
			lamp.insertedBattery = new Battery(true, 0f);
			lamp.isBeingUsed = false;
			lamp.itemUsedUp = false;
			Light[] componentsInChildren = ((Component)lamp).GetComponentsInChildren<Light>(true);
			foreach (Light val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null))
				{
					val.intensity = 0f;
					((Behaviour)val).enabled = false;
				}
			}
			MaterialPropertyBlock val2 = new MaterialPropertyBlock();
			Renderer[] componentsInChildren2 = ((Component)lamp).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val3 in componentsInChildren2)
			{
				if (!((Object)(object)val3 == (Object)null) && !((Object)((Component)val3).transform).name.StartsWith("ScanNode", StringComparison.OrdinalIgnoreCase))
				{
					val3.GetPropertyBlock(val2);
					val2.SetColor(EmissiveColorProperty, Color.black);
					val2.SetColor(EmissiveColorLdrProperty, Color.black);
					val2.SetColor(StandardEmissionColorProperty, Color.black);
					val2.SetFloat(EmissiveIntensityProperty, 0f);
					val3.SetPropertyBlock(val2);
					val2.Clear();
				}
			}
			if ((Object)(object)Item != (Object)null)
			{
				lamp.itemProperties = Item;
			}
			lamp.SetScrapValue(Mathf.Max(0, scrapValue));
			ScanNodeProperties componentInChildren = ((Component)lamp).GetComponentInChildren<ScanNodeProperties>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.headerText = "Discharged lamp";
			}
			RefreshLocalInventoryIcon(lamp);
		}

		internal static void CorrectSpawnedLampMesh()
		{
			//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)
			//IL_0071: 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_0080: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = (((Object)(object)Item != (Object)null) ? Item.spawnPrefab : null);
			Transform val2 = (((Object)(object)val != (Object)null) ? val.transform.Find("Model") : null);
			if (!((Object)(object)val2 == (Object)null))
			{
				Quaternion valueOrDefault = authoredModelRotation.GetValueOrDefault();
				if (!authoredModelRotation.HasValue)
				{
					valueOrDefault = val2.localRotation;
					authoredModelRotation = valueOrDefault;
				}
				val2.localRotation = authoredModelRotation.Value * Quaternion.Euler(SpawnedLampMeshCorrection);
			}
		}

		private static void RefreshLocalInventoryIcon(GrabbableObject lamp)
		{
			if ((Object)(object)Item == (Object)null || (Object)(object)Item.itemIcon == (Object)null || (Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)HUDManager.Instance == (Object)null)
			{
				return;
			}
			PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController;
			if ((Object)(object)localPlayerController == (Object)null || localPlayerController.ItemSlots == null)
			{
				return;
			}
			for (int i = 0; i < localPlayerController.ItemSlots.Length; i++)
			{
				if (!((Object)(object)localPlayerController.ItemSlots[i] != (Object)(object)lamp))
				{
					if (typeof(HUDManager).GetField("itemSlotIcons")?.GetValue(HUDManager.Instance) is Array array && i < array.Length)
					{
						object value = array.GetValue(i);
						value?.GetType().GetProperty("sprite")?.SetValue(value, Item.itemIcon);
					}
					break;
				}
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "Start")]
	internal static class SpawnedLampMeshPatch
	{
		[HarmonyPostfix]
		private static void CorrectSpawnedLampMesh()
		{
			DischargedLampRegistry.CorrectSpawnedLampMesh();
		}
	}
	public sealed class DischargedLampState : NetworkBehaviour
	{
		private const float ResolveTimeout = 15f;

		private const float MissingTargetDespawnDelay = 5f;

		private readonly NetworkVariable<NetworkObjectReference> targetLamp = new NetworkVariable<NetworkObjectReference>(default(NetworkObjectReference), (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<int> dischargedValue = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<bool> initialized = new NetworkVariable<bool>(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private Coroutine? resolveCoroutine;

		private float missingTargetTime;

		internal void Initialize(NetworkObjectReference lampReference, int scrapValue)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (!((NetworkBehaviour)this).IsServer || !((NetworkBehaviour)this).IsSpawned)
			{
				Plugin.Logger.LogError((object)"Tried to initialize a Discharged lamp state before its network object was spawned.");
				return;
			}
			targetLamp.Value = lampReference;
			dischargedValue.Value = Mathf.Max(0, scrapValue);
			initialized.Value = true;
			StartResolvingTarget();
		}

		public override void OnNetworkSpawn()
		{
			((NetworkBehaviour)this).OnNetworkSpawn();
			NetworkVariable<NetworkObjectReference> obj = targetLamp;
			obj.OnValueChanged = (OnValueChangedDelegate<NetworkObjectReference>)(object)Delegate.Combine((Delegate?)(object)obj.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<NetworkObjectReference>(OnTargetChanged));
			NetworkVariable<int> obj2 = dischargedValue;
			obj2.OnValueChanged = (OnValueChangedDelegate<int>)(object)Delegate.Combine((Delegate?)(object)obj2.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<int>(OnValueChanged));
			NetworkVariable<bool> obj3 = initialized;
			obj3.OnValueChanged = (OnValueChangedDelegate<bool>)(object)Delegate.Combine((Delegate?)(object)obj3.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<bool>(OnInitializedChanged));
			if (initialized.Value)
			{
				StartResolvingTarget();
			}
		}

		public override void OnNetworkDespawn()
		{
			NetworkVariable<NetworkObjectReference> obj = targetLamp;
			obj.OnValueChanged = (OnValueChangedDelegate<NetworkObjectReference>)(object)Delegate.Remove((Delegate?)(object)obj.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<NetworkObjectReference>(OnTargetChanged));
			NetworkVariable<int> obj2 = dischargedValue;
			obj2.OnValueChanged = (OnValueChangedDelegate<int>)(object)Delegate.Remove((Delegate?)(object)obj2.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<int>(OnValueChanged));
			NetworkVariable<bool> obj3 = initialized;
			obj3.OnValueChanged = (OnValueChangedDelegate<bool>)(object)Delegate.Remove((Delegate?)(object)obj3.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<bool>(OnInitializedChanged));
			if (resolveCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(resolveCoroutine);
				resolveCoroutine = null;
			}
			((NetworkBehaviour)this).OnNetworkDespawn();
		}

		private void Update()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (!((NetworkBehaviour)this).IsServer || !((NetworkBehaviour)this).IsSpawned || !initialized.Value)
			{
				return;
			}
			NetworkObjectReference value = targetLamp.Value;
			NetworkObject val = default(NetworkObject);
			if (((NetworkObjectReference)(ref value)).TryGet(ref val, (NetworkManager)null))
			{
				missingTargetTime = 0f;
				return;
			}
			missingTargetTime += Time.deltaTime;
			if (missingTargetTime >= 5f)
			{
				((NetworkBehaviour)this).NetworkObject.Despawn(true);
			}
		}

		private void OnTargetChanged(NetworkObjectReference previous, NetworkObjectReference current)
		{
			if (initialized.Value)
			{
				StartResolvingTarget();
			}
		}

		private void OnValueChanged(int previous, int current)
		{
			if (initialized.Value)
			{
				StartResolvingTarget();
			}
		}

		private void OnInitializedChanged(bool previous, bool current)
		{
			if (current)
			{
				StartResolvingTarget();
			}
		}

		private void StartResolvingTarget()
		{
			if (((NetworkBehaviour)this).IsSpawned && !TryApplyState())
			{
				if (resolveCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(resolveCoroutine);
				}
				resolveCoroutine = ((MonoBehaviour)this).StartCoroutine(ResolveTarget());
			}
		}

		private IEnumerator ResolveTarget()
		{
			float startedAt = Time.realtimeSinceStartup;
			while (((NetworkBehaviour)this).IsSpawned && initialized.Value && Time.realtimeSinceStartup - startedAt < 15f)
			{
				if (TryApplyState())
				{
					resolveCoroutine = null;
					yield break;
				}
				yield return null;
			}
			resolveCoroutine = null;
			if (((NetworkBehaviour)this).IsSpawned && initialized.Value)
			{
				Plugin.Logger.LogWarning((object)"Could not resolve the Fancy lamp for a replicated Discharged lamp state.");
			}
		}

		private bool TryApplyState()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (initialized.Value)
			{
				NetworkObjectReference value = targetLamp.Value;
				NetworkObject val = default(NetworkObject);
				GrabbableObject lamp = default(GrabbableObject);
				if (((NetworkObjectReference)(ref value)).TryGet(ref val, (NetworkManager)null) && ((Component)val).TryGetComponent<GrabbableObject>(ref lamp))
				{
					DischargedLampRegistry.ApplyState(lamp, dischargedValue.Value);
					return true;
				}
			}
			return false;
		}

		protected override void __initializeVariables()
		{
			if (targetLamp == null)
			{
				throw new Exception("DischargedLampState.targetLamp cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			((NetworkVariableBase)targetLamp).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)targetLamp, "targetLamp");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)targetLamp);
			if (dischargedValue == null)
			{
				throw new Exception("DischargedLampState.dischargedValue cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			((NetworkVariableBase)dischargedValue).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)dischargedValue, "dischargedValue");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)dischargedValue);
			if (initialized == null)
			{
				throw new Exception("DischargedLampState.initialized cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			((NetworkVariableBase)initialized).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)initialized, "initialized");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)initialized);
			((NetworkBehaviour)this).__initializeVariables();
		}

		protected override void __initializeRpcs()
		{
			((NetworkBehaviour)this).__initializeRpcs();
		}

		protected internal override string __getTypeName()
		{
			return "DischargedLampState";
		}
	}
	internal static class UtilityFlashlightInventory
	{
		internal const int UtilitySlotIndex = 50;

		private static readonly MethodInfo? SwitchToItemSlotMethod = AccessTools.Method(typeof(PlayerControllerB), "SwitchToItemSlot", new Type[2]
		{
			typeof(int),
			typeof(GrabbableObject)
		}, (Type[])null);

		private static readonly MethodInfo? SwitchToSlotServerRpcMethod = AccessTools.Method(typeof(PlayerControllerB), "SwitchToSlotServerRpc", new Type[1] { typeof(int) }, (Type[])null);

		private static readonly FieldInfo? ThrowingObjectField = AccessTools.Field(typeof(PlayerControllerB), "throwingObject");

		private static readonly FieldInfo? GrabbedObjectValidatedField = AccessTools.Field(typeof(PlayerControllerB), "grabbedObjectValidated");

		private static readonly FieldInfo? GrabInvalidatedField = AccessTools.Field(typeof(PlayerControllerB), "grabInvalidated");

		internal static bool IsInUtilitySlot(PlayerControllerB player, FlashlightItem flashlight)
		{
			if ((Object)(object)player != (Object)null && (Object)(object)flashlight != (Object)null)
			{
				return (Object)(object)player.ItemOnlySlot == (Object)(object)flashlight;
			}
			return false;
		}

		internal static int FindNormalSlot(PlayerControllerB player, FlashlightItem flashlight)
		{
			if (player.ItemSlots == null)
			{
				return -1;
			}
			for (int i = 0; i < player.ItemSlots.Length; i++)
			{
				if ((Object)(object)player.ItemSlots[i] == (Object)(object)flashlight)
				{
					return i;
				}
			}
			return -1;
		}

		internal static bool IsStoredByPlayer(PlayerControllerB player, FlashlightItem flashlight)
		{
			if (!IsInUtilitySlot(player, flashlight) && FindNormalSlot(player, flashlight) < 0 && !((Object)(object)player.pocketedFlashlight == (Object)(object)flashlight) && !((Object)(object)player.currentlyHeldObjectServer == (Object)(object)flashlight))
			{
				return (Object)(object)player.currentlyHeldObject == (Object)(object)flashlight;
			}
			return true;
		}

		internal static int FindStoredSlot(PlayerControllerB player, FlashlightItem flashlight)
		{
			if (IsInUtilitySlot(player, flashlight))
			{
				return 50;
			}
			return FindNormalSlot(player, flashlight);
		}

		internal static bool IsInActiveHand(PlayerControllerB player, FlashlightItem flashlight)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)flashlight == (Object)null || ((GrabbableObject)flashlight).isPocketed)
			{
				return false;
			}
			if (!((player.currentItemSlot != 50) ? (player.ItemSlots != null && player.currentItemSlot >= 0 && player.currentItemSlot < player.ItemSlots.Length && (Object)(object)player.ItemSlots[player.currentItemSlot] == (Object)(object)flashlight) : ((Object)(object)player.ItemOnlySlot == (Object)(object)flashlight)))
			{
				return false;
			}
			if (((NetworkBehaviour)player).IsOwner && !((Object)(object)player.currentlyHeldObjectServer == (Object)(object)flashlight))
			{
				return (Object)(object)player.currentlyHeldObject == (Object)(object)flashlight;
			}
			return true;
		}

		internal static bool SwitchToStoredFlashlight(PlayerControllerB player, FlashlightItem flashlight)
		{
			int num = FindStoredSlot(player, flashlight);
			if (SwitchToItemSlotMethod == null || SwitchToSlotServerRpcMethod == null || num < 0 || (num != 50 && (player.ItemSlots == null || num >= player.ItemSlots.Length)))
			{
				return false;
			}
			if (player.isGrabbingObjectAnimation || IsThrowingObject(player))
			{
				return false;
			}
			GrabbableObject currentlyHeldObjectServer = player.currentlyHeldObjectServer;
			FlashlightItem val = (FlashlightItem)(((object)((currentlyHeldObjectServer is FlashlightItem) ? currentlyHeldObjectServer : null)) ?? ((object)/*isinst with value type is only supported in some contexts*/));
			if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)flashlight && LightBatAI.IsFlashlightInteractionLocked(val))
			{
				return false;
			}
			try
			{
				SwitchToItemSlotMethod.Invoke(player, new object[2] { num, null });
				if (!IsInActiveHand(player, flashlight))
				{
					return false;
				}
				SwitchToSlotServerRpcMethod.Invoke(player, new object[1] { num });
				return true;
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Could not deploy a stored flashlight into hand: {arg}");
				return false;
			}
		}

		internal static bool IsThrowingObject(PlayerControllerB player)
		{
			object obj = ThrowingObjectField?.GetValue(player);
			if (obj is bool)
			{
				return (bool)obj;
			}
			return false;
		}

		internal static bool IsWaitingForGrabbedObject(PlayerControllerB player)
		{
			object obj = GrabbedObjectValidatedField?.GetValue(player);
			if (obj is bool)
			{
				return !(bool)obj;
			}
			return false;
		}

		internal static void InvalidateGrab(PlayerControllerB player)
		{
			GrabInvalidatedField?.SetValue(player, true);
		}
	}
	[HarmonyPatch(typeof(FlashlightItem), "ItemActivate")]
	internal static class LockedFlashlightActivationPatch
	{
		[HarmonyPrefix]
		private static bool AllowActivation(FlashlightItem __instance)
		{
			return !LightBatAI.IsFlashlightInteractionLocked(__instance);
		}
	}
	[HarmonyPatch(typeof(FlashlightItem), "PocketItem")]
	internal static class LockedFlashlightPocketPatch
	{
		[HarmonyPrefix]
		private static bool AllowPocketing(FlashlightItem __instance)
		{
			if (!LightBatAI.IsFlashlightInteractionLocked(__instance))
			{
				return true;
			}
			PlayerControllerB playerHeldBy = ((GrabbableObject)__instance).playerHeldBy;
			if ((Object)(object)playerHeldBy != (Object)null)
			{
				return !UtilityFlashlightInventory.IsInActiveHand(playerHeldBy, __instance);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(FlashlightItem), "Update")]
	internal static class LockedFlashlightUpdatePatch
	{
		[HarmonyPostfix]
		private static void KeepAttachedFlashlightOn(FlashlightItem __instance)
		{
			if (LightBatAI.IsFlashlightInteractionLocked(__instance) && ((GrabbableObject)__instance).insertedBattery != null && !((GrabbableObject)__instance).insertedBattery.empty && !(((GrabbableObject)__instance).insertedBattery.charge <= 0f))
			{
				((GrabbableObject)__instance).isBeingUsed = true;
				if ((Object)(object)__instance.flashlightBulb != (Object)null && !((Behaviour)__instance.flashlightBulb).enabled)
				{
					__instance.SwitchFlashlight(true);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "Update")]
	internal static class StalledGrabRecoveryPatch
	{
		private const float StalledGrabTimeout = 5f;

		private static float stallStartedAt = -1f;

		[HarmonyPostfix]
		private static void RecoverStalledGrab(PlayerControllerB __instance)
		{
			if (!((Object)(object)GameNetworkManager.Instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance.localPlayerController != (Object)(object)__instance))
			{
				if (!__instance.isGrabbingObjectAnimation || !UtilityFlashlightInventory.IsWaitingForGrabbedObject(__instance))
				{
					stallStartedAt = -1f;
				}
				else if (stallStartedAt < 0f)
				{
					stallStartedAt = Time.time;
				}
				else if (!(Time.time - stallStartedAt < 5f))
				{
					stallStartedAt = -1f;
					Plugin.Logger.LogWarning((object)($"A pickup has been stuck for {5f:0.#}s without " + "the item ever arriving. Cancelling it so the player is not left unable to interact."));
					UtilityFlashlightInventory.InvalidateGrab(__instance);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "BeginGrabObject")]
	internal static class LockedFlashlightGrabPatch
	{
		[HarmonyPrefix]
		private static bool AllowGrab(PlayerControllerB __instance)
		{
			GrabbableObject currentlyHeldObjectServer = __instance.currentlyHeldObjectServer;
			FlashlightItem val = (FlashlightItem)(((object)((currentlyHeldObjectServer is FlashlightItem) ? currentlyHeldObjectServer : null)) ?? ((object)/*isinst with value type is only supported in some contexts*/));
			if (!((Object)(object)val == (Object)null))
			{
				return !LightBatAI.IsFlashlightInteractionLocked(val);
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "SwitchToItemSlot")]
	internal static class LockedFlashlightInventorySlotPatch
	{
		[HarmonyPrefix]
		private static bool AllowSlotSwitch(PlayerControllerB __instance, int slot, GrabbableObject fillSlotWithItem)
		{
			if (!((NetworkBehaviour)__instance).IsOwner)
			{
				return true;
			}
			if ((Object)(object)fillSlotWithItem != (Object)null)
			{
				return true;
			}
			if (slot == __instance.currentItemSlot)
			{
				return true;
			}
			GrabbableObject currentlyHeldObjectServer = __instance.currentlyHeldObjectServer;
			FlashlightItem val = (FlashlightItem)(((object)((currentlyHeldObjectServer is FlashlightItem) ? currentlyHeldObjectServer : null)) ?? ((object)/*isinst with value type is only supported in some contexts*/));
			if (!((Object)(object)val == (Object)null))
			{
				return !LightBatAI.IsFlashlightInteractionLocked(val);
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "DiscardHeldObject")]
	internal static class LockedFlashlightDiscardPatch
	{
		[HarmonyPrefix]
		internal static bool AllowDiscard(PlayerControllerB __instance)
		{
			if (__instance.isPlayerDead)
			{
				return true;
			}
			GrabbableObject currentlyHeldObjectServer = __instance.currentlyHeldObjectServer;
			FlashlightItem val = (FlashlightItem)(((object)((currentlyHeldObjectServer is FlashlightItem) ? currentlyHeldObjectServer : null)) ?? ((object)/*isinst with value type is only supported in some contexts*/));
			if (!((Object)(object)val == (Object)null))
			{
				return !LightBatAI.IsFlashlightInteractionLocked(val);
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "Discard_performed")]
	internal static class LockedFlashlightDiscardInputPatch
	{
		[HarmonyPrefix]
		private static bool AllowDiscardInput(PlayerControllerB __instance)
		{
			return LockedFlashlightDiscardPatch.AllowDiscard(__instance);
		}
	}
	public sealed class LightBatAI : EnemyAI
	{
		private enum ApparatusPhase
		{
			None,
			Approaching,
			Perched,
			Hauling,
			Draining
		}

		private sealed class ApparatusFlock
		{
			public ulong ApparatusId;

			public LungProp Apparatus;

			public int Generation;

			public readonly List<LightBatAI> Members = new List<LightBatAI>();

			public ApparatusPhase Phase = ApparatusPhase.Approaching;

			public bool Ending;

			public int SimulatedFrame = -1;

			public PlayerControllerB? Holder;

			public GameObject NavObject;

			public NavMeshAgent Nav;

			public bool NavReady;

			public Vector3 HaulOrigin;

			public Vector3 HaulDestination;

			public bool HasHaulDestination;

			public float HaulStartedAt;

			public float HaulProgressAt;

			public Vector3 HaulProgressPosition;

			public float NextHaulReplanAt;

			public int HaulReplanCount;

			public float HaulHeight;

			public Vector3 CarryPosition;

			public Vector3 CarryFacing;

			public float CarryYaw;

			public int CarryTick;

			public float NextCarryPublishAt;

			public float PullStartedAt = -1f;

			public Vector3 PullDirection;

			public Vector3 PullDestination;

			public bool HasPullDestination;

			public float NextPullDestinationAt;

			public Vector3 PublishedPull;

			public Vector3 PullRouteDirection;

			public float NextPullRouteAt;

			public bool DrainActive;

			public bool DrainCompleted;

			public float DrainElapsed;

			public float NextDrainSyncAt;

			public float PhaseEnteredAt;

			public float PerchedSince = -1f;

			public float UnperchedSince = -1f;

			public int PublishedPerchedCount = -1;
		}

		private sealed class ApparatusHold
		{
			public ulong ApparatusId;

			public LungProp Apparatus;

			public int Generation;

			public GameObject AnchorObject;

			public Transform Anchor;

			public Vector3 SmoothPosition;

			public float SmoothYaw;

			public bool Primed;

			public int AppliedTick = int.MinValue;

			public int AppliedFrame = -1;

			public int TouchedFrame = -1;
		}

		private sealed class ApparatusLightVisualState
		{
			public LungProp Apparatus;

			public Light[] Lights;

			public float[] FullIntensities;
		}

		private sealed class ApparatusLiftState
		{
			public float Height;

			public float GroundY;

			public bool HasGround;

			public bool HoldingVertical;

			public int TouchedFrame = -1;
		}

		private sealed class ApparatusDrainProgress
		{
			public float Elapsed;

			public int StartValue;

			public int TargetValue;

			public bool Completed;
		}

		private sealed class ApparatusHoldDriver : MonoBehaviour
		{
			private void LateUpdate()
			{
				SweepOrphanedApparatusHolds();
			}
		}

		private sealed class ApparatusShape
		{
			public LungProp Apparatus;

			public Vector3 LocalCenter;

			public Vector3 Extents;
		}

		private sealed class BurnMeshState
		{
			public SkinnedMeshRenderer BodyRenderer;

			public SkinnedMeshRenderer EdgeRenderer;

			public Mesh OriginalMesh;

			public Mesh BodyMesh;

			public Mesh EdgeMesh;

			public int[][] SourceTriangles;

			public float[][] TriangleScores;

			public int[][] SortedTriangles;

			public float[][] SortedScores;

			public int EdgeMaterialCount;

			public int[] AppliedBodyCount;

			public int[] AppliedKeptCount;

			public bool BurnBuffersReady;
		}

		private sealed class BurnMeshAnalysis
		{
			public int[][] SourceTriangles;

			public float[][] TriangleScores;

			public int[][] SortedTriangles;

			public float[][] SortedScores;
		}

		private sealed class SharedFacilityLightState
		{
			public Animator Animator;

			public Light[] Lights;

			public float[] FullIntensities;

			public float RemainingEnergy = 1f;

			public float FlickerStartedAt;

			public float FlickerEndsAt;

			public readonly Dictionary<ulong, int> PerchSlots = new Dictionary<ulong, int>();

			public bool? HasOnParameter;
		}

		private sealed class FlashlightRaid
		{
			public ulong FlashlightId;

			public FlashlightItem Flashlight;

			public PlayerControllerB Player;

			public LightBatAI Volunteer;

			public readonly List<LightBatAI> Members = new List<LightBatAI>();

			public bool Ending;

			public int RaidGeneration;

			public bool DeployingFlashlight;

			public bool OwnerConfirmedEquipped;

			public int DeploymentRequestId;

			public float DeploymentStartedAt;

			public float NextDeploymentRequestAt;

			public float HandStableSince = -1f;

			public float HandLostSince = -1f;

			public float ReturnCooldown = 8f;
		}

		private sealed class LampVisualState
		{
			public Light[] Lights;

			public float[] FullIntensities;
		}

		private sealed class LampValueState
		{
			public GrabbableObject Lamp;

			public int OriginalScrapValue;
		}

		private enum State
		{
			SearchingForLight,
			FlyingToLight,
			Perching,
			Draining,
			Fleeing,
			FlyingToRaidFlashlight,
			AttachedToFlashlight,
			OrbitingFlashlightPlayer,
			FlyingToHeldApparatus,
			PerchedOnHeldApparatus,
			CarryingApparatus,
			FlyingToDroppedApparatus,
			DrainingApparatus
		}

		private enum TargetKind
		{
			None,
			FacilityLight,
			Flashlight,
			ItemLamp
		}

		private struct RaidFlashlightSearch
		{
			public FlashlightItem? Closest;

			public NetworkObject? ClosestNetworkObject;

			public float ClosestDistance;
		}

		private readonly struct TargetCandidate
		{
			public readonly TargetKind Kind;

			public readonly int FacilityIndex;

			public readonly FlashlightItem? Flashlight;

			public readonly GrabbableObject? Lamp;

			public readonly Vector3 Position;

			public readonly float StraightLineDistance;

			public TargetCandidate(TargetKind kind, int facilityIndex, FlashlightItem? flashlight, GrabbableObject? lamp, Vector3 position, float straightLineDistance)
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				Kind = kind;
				FacilityIndex = facilityIndex;
				Flashlight = flashlight;
				Lamp = lamp;
				Position = position;
				StraightLineDistance = straightLineDistance;
			}
		}

		private struct TargetChoice
		{
			public TargetKind Kind;

			public int FacilityIndex;

			public FlashlightItem? Flashlight;

			public GrabbableObject? Lamp;

			public Vector3 NavigationPosition;

			public Vector3 VisualPosition;

			public float PathDistance;
		}

		private const float ApparatusAttachDistance = 0.85f;

		private const float ApparatusApproachRepathInterval = 0.55f;

		private const float ApparatusApproachStallTime = 0.7f;

		private const float ApparatusApproachGiveUpTime = 7f;

		private const float ApparatusFlockAbandonTime = 20f;

		private const int ApparatusHoldSweepFrames = 12;

		private const float ApparatusMaximumPull = 4f;

		private const float ApparatusMaximumAirbornePull = 5.5f;

		private const float ApparatusLiftRiseRate = 1.1f;

		private const float ApparatusLiftFallRate = 2.6f;

		private const float ApparatusLiftStiffness = 6f;

		private const float ApparatusLiftMaximumVerticalSpeed = 4f;

		private const float ApparatusLiftPlayerHeight = 2.6f;

		private const float ApparatusLiftCeilingMargin = 0.3f;

		private const float ApparatusLiftMinimumHeight = 0.2f;

		private const float ApparatusLiftProbeAhead = 1.6f;

		private const float ApparatusLiftProbeCeiling = 8f;

		private const float ApparatusLiftGroundProbe = 12f;

		private const float ApparatusLiftGroundTrackRate = 3f;

		private const int ApparatusLiftExpiryFrames = 8;

		private const float ApparatusHaulStallTime = 0.7f;

		private const float ApparatusHaulReplanCooldown = 0.45f;

		private const float ApparatusHaulTimeout = 26f;

		private const float ApparatusHaulArriveDistance = 2.2f;

		private const float ApparatusHaulMinimumDisplacement = 7f;

		private const float ApparatusPerchSettleTime = 0.45f;

		private const float ApparatusReturnCooldown = 6f;

		private const float ApparatusDepletedCooldown = 14f;

		private const float ApparatusPullRampTime = 1.2f;

		private const float ApparatusPullDestinationInterval = 6f;

		private const float ApparatusDestinationSampleRadius = 3f;

		private const float ApparatusPullRouteInterval = 0.1f;

		private const float ApparatusCarryPublishInterval = 0.05f;

		private const float ApparatusDrainSyncInterval = 0.15f;

		private const float ApparatusDoorOpenCooldown = 1.1f;

		private const float ApparatusDoorScanDistance = 3.6f;

		private const int ApparatusSlotsPerRing = 5;

		private const int ApparatusFinalScrapMinimum = 30;

		private const int ApparatusFinalScrapMaximumExclusive = 46;

		private readonly NetworkVariable<NetworkObjectReference> syncedApparatus = new NetworkVariable<NetworkObjectReference>(default(NetworkObjectReference), (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)1);

		private readonly NetworkVariable<int> syncedApparatusPhase = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)1);

		private readonly NetworkVariable<int> syncedApparatusSlot = new NetworkVariable<int>(-1, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)1);

		private readonly NetworkVariable<int> syncedApparatusGeneration = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)1);

		private readonly NetworkVariable<int> syncedApparatusPerchedCount = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)1);

		private readonly NetworkVariable<Vector3> syncedApparatusPull = new NetworkVariable<Vector3>(Vector3.zero, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)1);

		private readonly NetworkVariable<Vector3> syncedApparatusCarryPosition = new NetworkVariable<Vector3>(Vector3.zero, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)1);

		private readonly NetworkVariable<float> syncedApparatusCarryYaw = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)1);

		private readonly NetworkVariable<int> syncedApparatusCarryTick = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)1);

		private static readonly Dictionary<ulong, ApparatusFlock> activeApparatusFlocks = new Dictionary<ulong, ApparatusFlock>();

		private static readonly Dictionary<ulong, ApparatusHold> apparatusHolds = new Dictionary<ulong, ApparatusHold>();

		private static readonly Dictionary<int, ApparatusLightVisualState> apparatusLightVisualStates = new Dictionary<int, ApparatusLightVisualState>();

		private static readonly Dictionary<int, float> nextApparatusDoorOpenTime = new Dictionary<int, float>();

		private static readonly Dictionary<ulong, int> apparatusPullFrame = new Dictionary<ulong, int>();

		private static readonly Dictionary<ulong, ApparatusDrainProgress> apparatusDrainProgress = new Dictionary<ulong, ApparatusDrainProgress>();

		private static readonly Dictionary<ulong, ApparatusLiftState> apparatusLiftStates = new Dictionary<ulong, ApparatusLiftState>();

		private static readonly List<ulong> apparatusLiftSweepBuffer = new List<ulong>();

		private static readonly RaycastHit[] apparatusLiftProbeHits = (RaycastHit[])(object)new RaycastHit[64];

		private static readonly Dictionary<int, bool> apparatusLiftProbeWorldColliders = new Dictionary<int, bool>();

		private static readonly Collider[] apparatusDoorProbeColliders = (Collider[])(object)new Collider[256];

		private static readonly Dictionary<int, DoorLock?> apparatusDoorColliders = new Dictionary<int, DoorLock>();

		private static readonly NavMeshPath apparatusRoutePath = new NavMeshPath();

		private static readonly HashSet<ulong> announcedApparatusDrains = new HashSet<ulong>();

		private static readonly List<ulong> apparatusHoldSweepBuffer = new List<ulong>();

		private static StartOfRound? apparatusSessionRound;

		private static int apparatusSessionSeed = int.MinValue;

		private static int apparatusSessionLevelId = int.MinValue;

		private static int apparatusHoldSweepFrame = -1;

		private static int nextApparatusFlockGeneration;

		private ApparatusFlock? activeApparatusFlock;

		private LungProp? cachedApparatus;

		private int apparatusSlot = -1;

		private bool apparatusActuallyPerched;

		private float nextApparatusFlockAllowedTime;

		private Vector3 apparatusApproachProgressPosition;

		private float apparatusApproachProgressAt;

		private float apparatusApproachStartedAt;

		private float nextApparatusApproachRepathAt;

		private Vector3 apparatusApproachDetour;

		private bool apparatusGroundPoseApplied;

		private static ApparatusHoldDriver? apparatusHoldDriver;

		private static readonly Dictionary<int, ApparatusShape> apparatusShapes = new Dictionary<int, ApparatusShape>();

		[Header("LightBat")]
		public Transform visualRoot;

		public AudioClip[] flapSounds;

		public AudioClip burningSound;

		public Material burnEdgeMaterial;

		private const float PerchDistance = 1.1f;

		private const float MovingTargetBreakDistance = 2.2f;

		private const float FacilityPerchOffset = 0.25f;

		private const float DroppedFlashlightPerchOffset = 0.65f;

		private const float ItemLampPerchOffset = 0.28f;

		private const int CarriedLightTier = 0;

		private const int FacilityLightTier = 1;

		private const float WeaveProbeInterval = 0.1f;

		private const float CandidateRangeSlack = 12f;

		private const int MaxPathChecksPerSearch = 12;

		private const float ItemScanInterval = 0.5f;

		private const float DischargedLampValueMultiplier = 0.4f;

		private const float MinimumFlightHeight = 0.65f;

		private const float NavMeshProjectionRadius = 3f;

		private const float MaximumTargetNavOffset = 1.15f;

		private const float FinalObstacleReleaseDistance = 1.35f;

		private const float ModelHalfHeight = 0.62f;

		private const float ModelCollisionRadius = 0.48f;

		private const float FacilityTargetStuckTime = 4f;

		private const float FailedFacilityTargetCooldown = 600f;

		private const float CruiseHeightVariation = 0.72f;

		private const float HeightLaneStep = 0.618034f;

		private const float ClearanceLookAheadDistance = 3.8f;

		private const float ClearanceProbeSpacing = 0.55f;

		private const float ClearanceProbeRadius = 0.2f;

		private const float FinalPathProbeRadius = 0.16f;

		private const float FinalTargetAllowance = 0.28f;

		private const float HitFearLevel = 0.7f;

		private const float FleeSafeDistance = 16f;

		private const float FleeMinimumTime = 1.5f;

		private const float FleeMaximumTime = 10f;

		private const float FleeRepathInterval = 0.75f;

		private const float FleeSpeedMultiplier = 1.85f;

		private const float LandingFlickerDuration = 0.7f;

		private const float SharedLampPerchRadius = 0.28f;

		private const float AdditionalPerchRingSpacing = 0.42f;

		private const int PerchSlotsPerRing = 12;

		private const float ActiveAgentRadius = 0.5f;

		private const float PerchedAgentRadius = 0.05f;

		private const float RaidAttachDistance = 0.62f;

		private const float RaidFlashlightForwardOffset = 0.16f;

		private const float RaidFlashlightVerticalOffset = 0.22f;

		private const float RaidOrbitRadius = 3.1f;

		private const float RaidOrbitRingSpacing = 0.42f;

		private const int RaidOrbitSlotsPerRing = 8;

		private const float RaidOrbitDegreesPerSecond = 38f;

		private const float RaidReturnCooldown = 8f;

		private const float RaidStressLevel = 0.24f;

		private const float RaidStressInterval = 0.65f;

		private const float FlashlightDeploymentRetryInterval = 0.65f;

		private const float FlashlightDeploymentTimeout = 7f;

		private const float FlashlightHandSettleTime = 0.3f;

		private const float FlashlightDeploymentFailureCooldown = 1.25f;

		private const float RaidHandLossGrace = 0.6f;

		private const float FlapSoundVolume = 0.55f;

		private const float MinimumFlapPitch = 1.25f;

		private const float MaximumFlapPitch = 1.4f;

		private const float EnergizedDuration = 10f;

		private const float EnergizedSpeedMultiplier = 1.65f;

		private const float EnergizedAnimationSpeed = 1.25f;

		private const float SunlightBurnSoundVolume = 0.85f;

		private const float SunlightBurnEdgeWidth = 0.055f;

		private const int SunlightBurnIgnitionPointCount = 7;

		private const float MinimumVisualBoundsExtent = 2.5f;

		private const int EyeGlowMaterialIndex = 1;

		private static readonly int EmissiveColorProperty = Shader.PropertyToID("_EmissiveColor");

		private static readonly int EmissiveColorLdrProperty = Shader.PropertyToID("_EmissiveColorLDR");

		private static readonly int EmissiveIntensityProperty = Shader.PropertyToID("_EmissiveIntensity");

		private static readonly int StandardEmissionColorProperty = Shader.PropertyToID("_EmissionColor");

		private static readonly Color EyeEnergyColor = new Color(1f, 0.5f, 0.14f, 1f);

		private static readonly int[] PerchSlotOrder = new int[12]
		{
			0, 6, 3, 9, 1, 7, 4, 10, 2, 8,
			5, 11
		};

		private readonly NetworkVariable<bool> syncedFinalClimb = new NetworkVariable<bool>(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)1);

		private readonly NetworkVariable<float> syncedCruiseHeightOffset = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)1);

		private readonly NetworkVariable<NetworkObjectReference> syncedRaidFlashlight = new NetworkVariable<NetworkObjectReference>(default(NetworkObjectReference), (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)1);

		private readonly NetworkVariable<NetworkObjectReference> syncedBurnFlashlight = new NetworkVariable<NetworkObjectReference>(default(NetworkObjectReference), (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)1);

		private readonly NetworkVariable<NetworkObjectReference> syncedBurnLamp = new NetworkVariable<NetworkObjectReference>(default(NetworkObjectReference), (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)1);

		private readonly NetworkVariable<NetworkObjectReference> syncedBurnApparatus = new NetworkVariable<NetworkObjectReference>(default(NetworkObjectReference), (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)1);

		private readonly NetworkVariable<int> syncedBurnApparatusSlot = new NetworkVariable<int>(-1, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)1);

		private readonly NetworkVariable<bool> syncedEnergized = new NetworkVariable<bool>(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)1);

		private readonly NetworkVariable<bool> syncedBurningOut = new NetworkVariable<bool>(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)1);

		private readonly NetworkVariable<float> syncedDissolveProgress = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)1);

		private readonly AISearchRoutine wideSearch = new AISearchRoutine
		{
			loopSearch = true,
			searchWidth = 200f,
			searchPrecision = 12f,
			randomized = true
		};

		private readonly Dictionary<int, float> blockedFacilityTargets = new Dictionary<int, float>();

		private TargetKind targetKind;

		private int targetFacilityLightIndex = -1;

		private FlashlightItem? targetFlashlight;

		private GrabbableObject? targetLamp;

		private PlayerControllerB? fleeFromPlayer;

		private Vector3 fleeDestination;

		private float nextFleeRepathTime;

		private float stateTimer;

		private float retargetCooldown;

		private Vector3 visualRootStartPosition;

		private Vector3 targetNavigationPosition;

		private float targetPathDistance;

		private float bestTargetPathDistance;

		private float timeAtLastTargetProgress;

		private float smoothedVerticalSpeed;

		private float smoothedYaw;

		private float yawVelocity;

		private float previousRootYaw;

		private float smoothedVisualTurnRate;

		private Vector3 previousRootPosition;

		private float smoothedRootSpeed;

		private Renderer? eyeGlowRenderer;

		private MaterialPropertyBlock? eyeGlowProperties;

		private float appliedEyeGlow = -1f;

		private float nextWeaveProbeTime;

		private float cachedWeaveLimit;

		private float cachedWeaveSign;

		private bool boundsFollowSkeleton = true;

		private float eyeGlowCharge;

		private static int heightLaneSequence;

		private float nextClearanceProbeTime;

		private float cachedSafeFlightHeight = float.PositiveInfinity;

		private Coroutine? facilityDrainCoroutine;

		private Coroutine? facilityFlickerCoroutine;

		private Coroutine? flashlightDrainCoroutine;

		private Coroutine? lampDrainCoroutine;

		private Coroutine? flashlightDeploymentCoroutine;

		private int nextFlashlightDeploymentRequestId;

		private int activeLocalFlashlightDeploymentGeneration;

		private int latestCancelledFlashlightRaidGeneration;

		private int localRaidAttachmentGeneration;

		private ulong activeLampDrainId;

		private bool hasActiveLampDrain;

		private float lastHitSoundTime = float.NegativeInfinity;

		private int reservedFacilityAnimatorId = -1;

		private ulong reservedPerchOwnerId;

		private int reservedPerchSlot = -1;

		private Vector3 reservedPerchOffset;

		private int reservedLampInstanceId = -1;

		private FlashlightRaid? activeFlashlightRaid;

		private bool isFlashlightRaidVolunteer;

		private FlashlightItem? cachedRaidFlashlight;

		private FlashlightItem? cachedBurnFlashlight;

		private LungProp? cachedBurnApparatus;

		private GrabbableObject? cachedBurnLamp;

		private int flashlightRaidOrbitSlot = -1;

		private float nextFlashlightRaidAllowedTime;

		private float nextRaidStressPulseTime;

		private bool attachedAnimationEnabled;

		private bool wingFlapTrackingActive;

		private float previousWingCycle;

		private int lastFlapSoundIndex = -1;

		private float energizedUntilTime;

		private bool deathFallInitialized;

		private bool deathFallSettled;

		private float deathFallSpeed;

		private float deathGroundY;

		private float deathSettleTimer;

		private float deathPoseSink;

		private Mesh? deathPoseMesh;

		private SkinnedMeshRenderer? deathPoseRenderer;

		private const float DeathPoseSettleTime = 1.5f;

		private float displayedDissolveProgress;

		private bool burnPlaybackInitialized;

		private bool burnMaterialApplied;

		private bool burningAudioStarted;

		private AudioSource? burningAudioSource;

		private readonly List<BurnMeshState> burnMeshes = new List<BurnMeshState>();

		private MaterialPropertyBlock? burnProperties;

		private static readonly Dictionary<int, BurnMeshAnalysis> burnAnalysisCache = new Dictionary<int, BurnMeshAnalysis>();

		private static readonly Dictionary<int, SharedFacilityLightState> sharedFacilityLights = new Dictionary<int, SharedFacilityLightState>();

		private static readonly List<LightBatAI> liveBats = new List<LightBatAI>();

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

		private static readonly List<LightBatAI> raidCandidateScratch = new List<LightBatAI>();

		private readonly List<TargetCandidate> candidateBuffer = new List<TargetCandidate>();

		private NavMeshPath? reusableCandidatePath;

		private static readonly List<FlashlightItem> cachedFlashlights = new List<FlashlightItem>();

		private static readonly List<GrabbableObject> cachedGrabbables = new List<GrabbableObject>();

		private static readonly List<LungProp> cachedApparatuses = new List<LungProp>();

		private static float itemScanRefreshedAt = -1f;

		private static readonly RaycastHit[] perchProbeHits = (RaycastHit[])(object)new RaycastHit[32];

		private static readonly int FlyStateHash = Animator.StringToHash("Fly");

		private static readonly int AttachedToLightStateHash = Animator.StringToHash("AttachedToLight");

		private int animatorStateFrame = -1;

		private AnimatorStateInfo cachedAnimatorState;

		private bool cachedAnimatorStateValid;

		private int flightProgressFrame = -1;

		private float cachedFlightProgress;

		private static readonly Dictionary<int, Light[]> facilityLightCache = new Dictionary<int, Light[]>();

		private static readonly Dictionary<int, Light[]> itemLampLightCache = new Dictionary<int, Light[]>();

		private static readonly Dictionary<int, bool> itemLampIdentityCache = new Dictionary<int, bool>();

		private static readonly Dictionary<ulong, FlashlightRaid> activeFlashlightRaids = new Dictionary<ulong, FlashlightRaid>();

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

		private static readonly Dictionary<int, ulong> reservedItemLamps = new Dictionary<int, ulong>();

		private static readonly HashSet<ulong> activeLampDrains = new HashSet<ulong>();

		private static readonly Dictionary<int, LampVisualState> lampVisualStates = new Dictionary<int, LampVisualState>();

		private static readonly Dictionary<ulong, LampValueState> lampValueStates = new Dictionary<ulong, LampValueState>();

		private static Vector3[] pathCornerBuffer = (Vector3[])(object)new Vector3[64];

		private bool ApparatusPoseIsGrounded => apparatusGroundPoseApplied;

		private void ResetApparatusSupportLocally()
		{
			//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)
			EnsureApparatusSessionState();
			activeApparatusFlock = null;
			cachedApparatus = null;
			apparatusSlot = -1;
			apparatusActuallyPerched = false;
			apparatusApproachDetour = Vector3.zero;
			nextApparatusApproachRepathAt = 0f;
			ClearApparatusGroundDrainPose();
		}

		private static void EnsureApparatusSessionState()
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null || (apparatusSessionRound == instance && apparatusSessionSeed == instance.randomMapSeed && apparatusSessionLevelId == instance.currentLevelID))
			{
				return;
			}
			apparatusSessionRound = instance;
			apparatusSessionSeed = instance.randomMapSeed;
			apparatusSessionLevelId = instance.currentLevelID;
			foreach (ApparatusFlock value in activeApparatusFlocks.Values)
			{
				DestroyApparatusNav(value);
			}
			foreach (ApparatusHold value2 in apparatusHolds.Values)
			{
				if ((Object)(object)value2.AnchorObject != (Object)null)
				{
					Object.Destroy((Object)(object)value2.AnchorObject);
				}
			}
			activeApparatusFlocks.Clear();
			apparatusHolds.Clear();
			apparatusLightVisualStates.Clear();
			apparatusShapes.Clear();
			nextApparatusDoorOpenTime.Clear();
			apparatusDoorColliders.Clear();
			apparatusLiftProbeWorldColliders.Clear();
			apparatusPullFrame.Clear();
			apparatusDrainProgress.Clear();
			apparatusLiftStates.Clear();
			announcedApparatusDrains.Clear();
			apparatusHoldSweepBuffer.Clear();
			apparatusLiftSweepBuffer.Clear();
			nextApparatusFlockGeneration = 0;
		}

		private void ResetSyncedApparatusState()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			if (((NetworkBehaviour)this).IsOwner && ((NetworkBehaviour)this).IsSpawned)
			{
				syncedApparatus.Value = default(NetworkObjectReference);
				syncedApparatusPhase.Value = 0;
				syncedApparatusSlot.Value = -1;
				syncedApparatusGeneration.Value = 0;
				syncedApparatusPerchedCount.Value = 0;
				syncedApparatusPull.Value = Vector3.zero;
				syncedApparatusCarryPosition.Value = Vector3.zero;
				syncedApparatusCarryYaw.Value = 0f;
				syncedApparatusCarryTick.Value = 0;
			}
		}

		private bool TryStartOrJoinApparatusFlock()
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			EnsureApparatusSessionState();
			if (!((NetworkBehaviour)this).IsServer || activeApparatusFlock != null || activeFlashlightRaid != null || (Object)(object)StartOfRound.Instance == (Object)null || base.isEnemyDead || syncedBurningOut.Value || Time.time < nextApparatusFlockAllowedTime)
			{
				return false;
			}
			float num = Mathf.Max(5f, 30f);
			LungProp val = null;
			NetworkObject val2 = null;
			float num2 = num;
			NetworkObject val3 = default(NetworkObject);
			foreach (LungProp cachedApparatus in GetCachedApparatuses())
			{
				if (ApparatusIsAvailable(cachedApparatus) && ((Component)cachedApparatus).TryGetComponent<NetworkObject>(ref val3) && val3.IsSpawned)
				{
					float num3 = Vector3.Distance(((Component)this).transform.position, GetApparatusCenter(cachedApparatus));
					if (!(num3 >= num2))
					{
						val = cachedApparatus;
						val2 = val3;
						num2 = num3;
					}
				}
			}
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				return false;
			}
			ulong networkObjectId = val2.NetworkObjectId;
			if (activeApparatusFlocks.TryGetValue(networkObjectId, out ApparatusFlock value))
			{
				if (value.Ending || (Object)(object)value.Apparatus == (Object)null)
				{
					EndApparatusFlock(value, depleted: false);
					activeApparatusFlocks.Remove(networkObjectId);
					return false;
				}
				JoinApparatusFlock(value);
				return true;
			}
			ApparatusFlock apparatusFlock = new ApparatusFlock
			{
				ApparatusId = networkObjectId,
				Apparatus = val,
				Generation = ++nextApparatusFlockGeneration,
				Phase = ApparatusPhase.Approaching,
				PhaseEnteredAt = Time.time,
				Holder = (((GrabbableObject)val).isHeld ? ((GrabbableObject)val).playerHeldBy : null)
			};
			activeApparatusFlocks[networkObjectId] = apparatusFlock;
			for (int i = 0; i < liveBats.Count; i++)
			{
				LightBatAI lightBatAI = liveBats[i];
				if ((Object)(object)lightBatAI != (Object)null && lightBatAI.CanJoinApparatusFlock(val))
				{
					lightBatAI.JoinApparatusFlock(apparatusFlock);
				}
			}
			if (apparatusFlock.Members.Count == 0)
			{
				activeApparatusFlocks.Remove(networkObjectId);
				return false;
			}
			return true;
		}

		private bool CanJoinApparatusFlock(LungProp apparatus)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if (!((NetworkBehaviour)this).IsOwner || !((NetworkBehaviour)this).IsServer || !((NetworkBehaviour)this).IsSpawned || base.isEnemyDead || syncedBurningOut.Value || activeApparatusFlock != null || activeFlashlightRaid != null || base.currentBehaviourStateIndex == 4 || Time.time < nextApparatusFlockAllowedTime || !ApparatusIsAvailable(apparatus))
			{
				return false;
			}
			return Vector3.Distance(((Component)this).transform.position, GetApparatusCenter(apparatus)) <= Mathf.Max(5f, 30f);
		}

		private static bool ApparatusIsAvailable(LungProp apparatus)
		{
			if ((Object)(object)apparatus == (Object)null || !((Component)apparatus).gameObject.activeInHierarchy || !apparatus.isLungPowered || ((GrabbableObject)apparatus).scrapValue <= 0 || ((GrabbableObject)apparatus).isPocketed || ((GrabbableObject)apparatus).deactivated)
			{
				return false;
			}
			if (ApparatusIsDocked(apparatus))
			{
				return false;
			}
			if (((GrabbableObject)apparatus).isHeld || (Object)(object)((GrabbableObject)apparatus).playerHeldBy != (Object)null)
			{
				PlayerControllerB playerHeldBy = ((GrabbableObject)apparatus).playerHeldBy;
				if ((Object)(object)playerHeldBy != (Object)null && playerHeldBy.isPlayerControlled && !playerHeldBy.isPlayerDead && playerHeldBy.isInsideFactory)
				{
					return !playerHeldBy.isInHangarShipRoom;
				}
				return false;
			}
			if (((GrabbableObject)apparatus).isInFactory && !((GrabbableObject)apparatus).isInShipRoom)
			{
				return !((GrabbableObject)apparatus).isInElevator;
			}
			return false;
		}

		private static bool ApparatusIsPlayerHeld(LungProp apparatus)
		{
			if ((Object)(object)apparatus != (Object)null && ((GrabbableObject)apparatus).isHeld && !((GrabbableObject)apparatus).isPocketed)
			{
				return (Object)(object)((GrabbableObject)apparatus).playerHeldBy != (Object)null;
			}
			return false;
		}

		private static bool ApparatusIsDocked(LungProp apparatus)
		{
			if ((Object)(object)apparatus != (Object)null)
			{
				if (!apparatus.isLungDocked)
				{
					return apparatus.isLungDockedInElevator;
				}
				return true;
			}
			return false;
		}

		private static bool ApparatusHasLeftFacility(LungProp apparatus)
		{
			if ((Object)(object)apparatus == (Object)null)
			{
				return false;
			}
			if (((GrabbableObject)apparatus).isHeld && (Object)(object)((GrabbableObject)apparatus).playerHeldBy != (Object)null)
			{
				return !((GrabbableObject)apparatus).playerHeldBy.isInsideFactory;
			}
			if (((GrabbableObject)apparatus).isInFactory && !((GrabbableObject)apparatus).isInShipRoom)
			{
				return ((GrabbableObject)apparatus).isInElevator;
			}
			return true;
		}

		private void JoinApparatusFlock(ApparatusFlock flock)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: 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)
			if (base.currentSearch.inProgress)
			{
				((EnemyAI)this).StopSearch(base.currentSearch, true);
			}
			if (base.currentBehaviourStateIndex == 3)
			{
				CancelActiveDrainServerRpc();
			}
			ClearTarget();
			activeApparatusFlock = flock;
			cachedApparatus = flock.Apparatus;
			apparatusSlot = FindOpenApparatusSlot(flock);
			apparatusActuallyPerched = false;
			apparatusApproachProgressPosition = ((Component)this).transform.position;
			apparatusApproachProgressAt = Time.time;
			apparatusApproachStartedAt = Time.time;
			nextApparatusApproachRepathAt = 0f;
			apparatusApproachDetour = Vector3.zero;
			flock.Members.Add(this);
			flock.UnperchedSince = -1f;
			PublishApparatusState(flock, ApparatusPhase.Approaching);
			TransitionTo((flock.Phase == ApparatusPhase.Draining) ? State.FlyingToDroppedApparatus : State.FlyingToHeldApparatus);
		}

		private static int FindOpenApparatusSlot(ApparatusFlock flock)
		{
			int num = 0;
			bool flag;
			do
			{
				flag = false;
				foreach (LightBatAI member in flock.Members)
				{
					if ((Object)(object)member != (Object)null && member.apparatusSlot == num)
					{
						flag = true;
						num++;
						break;
					}
				}
			}
			while (flag);
			return num;
		}

		private void PublishApparatusState(ApparatusFlock flock, ApparatusPhase phase)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			NetworkObject val = default(NetworkObject);
			if (((NetworkBehaviour)this).IsOwner && ((NetworkBehaviour)this).IsSpawned && !((Object)(object)flock.Apparatus == (Object)null) && ((Component)flock.Apparatus).TryGetComponent<NetworkObject>(ref val) && val.IsSpawned)
			{
				syncedApparatus.Value = new NetworkObjectReference(val);
				syncedApparatusPhase.Value = (int)phase;
				syncedApparatusSlot.Value = apparatusSlot;
				syncedApparatusGeneration.Value = flock.Generation;
			}
		}

		private bool TryGetValidApparatusFlock(out ApparatusFlock flock)
		{
			flock = activeApparatusFlock;
			if (flock != null && !flock.Ending && (Object)(object)flock.Apparatus != (Object)null && flock.Members.Contains(this) && activeApparatusFlocks.TryGetValue(flock.ApparatusId, out ApparatusFlock value))
			{
				return value == flock;
			}
			return false;
		}

		private void UpdateApparatusFlockSimulation()
		{
			if (((NetworkBehaviour)this).IsServer && TryGetValidApparatusFlock(out ApparatusFlock flock) && flock.SimulatedFrame != Time.frameCount)
			{
				flock.SimulatedFrame = Time.frameCount;
				SimulateApparatusFlock(flock);
			}
		}

		private void SimulateApparatusFlock(ApparatusFlock flock)
		{
			LungProp apparatus = flock.Apparatus;
			if ((Object)(object)apparatus == (Object)null || ((GrabbableObject)apparatus).deactivated)
			{
				EndApparatusFlock(flock, depleted: false);
				return;
			}
			PruneApparatusFlockMembers(flock);
			if (flock.Members.Count == 0)
			{
				EndApparatusFlock(flock, depleted: false);
				return;
			}
			int num = CountPerchedApparatusBats(flock);
			PublishApparatusPerchedCount(flock, num);
			bool flag = ApparatusIsPlayerHeld(apparatus);
			flock.Holder = (flag ? ((GrabbableObject)apparatus).playerHeldBy : null);
			if (!ApparatusIsAvailable(apparatus))
			{
				bool burnMembers = apparatus.isLungPowered && !((GrabbableObject)apparatus).deactivated && ApparatusHasLeftFacility(apparatus);
				EndApparatusFlock(flock, depleted: false, burnMembers);
				return;
			}
			if (flag)
			{
				if (flock.Phase != ApparatusPhase.Perched)
				{
					ReleaseApparatusCustody(flock, dropToFloor: false);
					flock.DrainActive = false;
					SetApparatusPhase(flock, ApparatusPhase.Perched);
				}
				UpdateApparatusPull(flock, num);
				return;
			}
			ClearApparatusPull(flock);
			switch (flock.Phase)
			{
			case ApparatusPhase.Approaching:
			case ApparatusPhase.Perched:
				if (num <= 0)
				{
					flock.PerchedSince = -1f;
					if (flock.UnperchedSince < 0f)
					{
						flock.UnperchedSince = Time.time;
					}
					else if (Time.time - flock.UnperchedSince >= 20f)
					{
						EndApparatusFlock(flock, depleted: false);
					}
					break;
				}
				flock.UnperchedSince = -1f;
				if (flock.PerchedSince < 0f)
				{
					flock.PerchedSince = Time.time;
				}
				if (!(Time.time - flock.PerchedSince < 0.45f))
				{
					if (ApparatusIsDocked(apparatus))
					{
						SetApparatusPhase(flock, ApparatusPhase.Draining);
					}
					else
					{
						BeginApparatusHaul(flock);
					}
				}
				break;
			case ApparatusPhase.Hauling:
				UpdateApparatusHaul(flock, num);
				break;
			case ApparatusPhase.Draining:
				UpdateApparatusDrain(flock, num);
				break;
			}
		}

		private void PruneApparatusFlockMembers(ApparatusFlock flock)
		{
			for (int num = flock.Members.Count - 1; num >= 0; num--)
			{
				LightBatAI lightBatAI = flock.Members[num];
				if ((Object)(object)lightBatAI == (Object)null)
				{
					flock.Members.RemoveAt(num);
				}
				else if (((EnemyAI)lightBatAI).isEnemyDead || lightBatAI.syncedBurningOut.Value || lightBatAI.activeApparatusFlock != flock)
				{
					flock.Members.RemoveAt(num);
					if (lightBatAI.activeApparatusFlock == flock)
					{
						lightBatAI.DetachFromApparatusFlock(6f);
					}
				}
			}
		}

		private static int CountPerchedApparatusBats(ApparatusFlock flock)
		{
			int num = 0;
			foreach (LightBatAI member in flock.Members)
			{
				if ((Object)(object)member != (Object)null && !((EnemyAI)member).isEnemyDead && member.apparatusActuallyPerched)
				{
					num++;
				}
			}
			return num;
		}

		private static void PublishApparatusPerchedCount(ApparatusFlock flock, int perched)
		{
			flock.PublishedPerchedCount = perched;
			foreach (LightBatAI member in flock.Members)
			{
				if ((Object)(object)member != (Object)null && ((NetworkBehaviour)member).IsOwner && ((NetworkBehaviour)member).IsSpawned && member.syncedApparatusPerchedCount.Value != perched)
				{
					member.syncedApparatusPerchedCount.Value = perched;
				}
			}
		}

		private void SetApparatusPhase(ApparatusFlock flock, ApparatusPhase phase)
		{
			if (flock.Phase == phase)
			{
				return;
			}
			flock.Phase = phase;
			flock.PhaseEnteredAt = Time.time;
			flock.PerchedSince = -1f;
			State state = phase switch
			{
				ApparatusPhase.Hauling => State.CarryingApparatus, 
				ApparatusPhase.Draining => State.DrainingApparatus, 
				ApparatusPhase.Perched => State.PerchedOnHeldApparatus, 
				_ => State.FlyingToHeldApparatus, 
			};
			foreach (LightBatAI member in flock.Members)
			{
				if (!((Object)(object)member == (Object)null) && !((EnemyAI)member).isEnemyDead)
				{
					if (!member.apparatusActuallyPerched)
					{
						member.PublishApparatusState(flock, ApparatusPhase.Approaching);
						continue;
					}
					member.PublishApparatusState(flock, phase);
					member.TransitionTo(state);
				}
			}
		}

		private void FlyToApparatus()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: 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)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: 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_00e6: 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)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			if (!TryGetValidApparatusFlock(out ApparatusFlock flock))
			{
				DetachFromApparatusFlock(6f);
				return;
			}
			LungProp apparatus = flock.Apparatus;
			if (!ApparatusIsAvailable(apparatus))
			{
				return;
			}
			Vector3 apparatusAttachmentPosition = GetApparatusAttachmentPosition(apparatus, apparatusSlot);
			float num = Vector3.Distance(((Component)this).transform.position, apparatusAttachmentPosition);
			if (num <= 0.85f)
			{
				AttachToApparatus(flock);
				return;
			}
			OpenApparatusDoorsAhead(((Component)this).transform.position, apparatusAttachmentPosition - ((Component)this).transform.position, 3.6f);
			if (Vector3.Distance(((Component)this).transform.position, apparatusApproachProgressPosition) >= 0.35f)
			{
				apparatusApproachProgressPosition = ((Component)this).transform.position;
				apparatusApproachProgressAt = Time.time;
				apparatusApproachDetour = Vector3.zero;
			}
			else if (Time.time - apparatusApproachProgressAt >= 0.7f)
			{
				apparatusApproachProgressAt = Time.time;
				apparatusApproachDetour = PickApparatusDetour(apparatusAttachmentPosition);
				nextApparatusApproachRepathAt = 0f;
				if ((Object)(object)base.agent != (Object)null && ((Behaviour)base.agent).enabled && base.agent.isOnNavMesh)
				{
					base.agent.ResetPath();
				}
				if (Time.time - apparatusApproachStartedAt >= 7f)
				{
					LeaveApparatusFlock(flock, 6f);
					return;
				}
			}
			Vector3 targetPosition = apparatusAttachmentPosition + apparatusApproachDetour;
			if (Time.time >= nextApparatusApproachRepathAt || targetNavigationPosition == Vector3.zero)
			{
				nextApparatusApproachRepathAt = Time.time + 0.55f;
				if (!TryGetReachableNavigationPosition(targetPosition, out targetNavigationPosition, out targetPathDistance) && !TryGetReachableNavigationPosition(apparatusAttachmentPosition, out targetNavigationPosition, out targetPathDistance))
				{
					targetNavigationPosition = apparatusAttachmentPosition;
					targetPathDistance = num;
				}
			}
			SyncVisualTargetHeight(apparatusAttachmentPosition);
			if ((Object)(object)base.agent != (Object)null)
			{
				base.agent.speed = 3.4f;
			}
			((EnemyAI)this).SetDestinationToPosition(targetNavigationPosition, false);
		}

		private Vector3 PickApparatusDetour(Vector3 attachPosition)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_0039: 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)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = attachPosition - ((Component)this).transform.position;
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				return Vector3.zero;
			}
			Vector3 val2 = Vector3.Cross(Vector3.up, ((Vector3)(ref val)).normalized);
			float num = ((Random.value < 0.5f) ? (-1f) : 1f);
			return val2 * (num * Random.Range(1.6f, 3.2f));
		}

		private void AttachToApparatus(ApparatusFlock flock)
		{
			//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)
			StopMoving();
			PrepareForFlashlightAttachment();
			apparatusActuallyPerched = true;
			apparatusApproachDetour = Vector3.zero;
			ApparatusPhase apparatusPhase = ((flock.Phase == ApparatusPhase.Approaching) ? ApparatusPhase.Perched : flock.Phase);
			PublishApparatusState(flock, apparatusPhase);
			TransitionTo(apparatusPhase switch
			{
				ApparatusPhase.Hauling => State.CarryingApparatus, 
				ApparatusPhase.Draining => State.DrainingApparatus, 
				_ => State.PerchedOnHeldApparatus, 
			});
			LockToApparatus(flock.Apparatus, apparatusSlot);
		}

		private void UpdateApparatusPull(ApparatusFlock flock, int perched)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_0037: 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)
			//IL_00a9: 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)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: 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_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: 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_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Invalid comparison between Unknown and I4
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			if (perched <= 0 || (Object)(object)flock.Holder == (Object)null)
			{
				ClearApparatusPull(flock);
				return;
			}
			if (flock.PullStartedAt < 0f)
			{
				flock.PullStartedAt = Time.time;
				flock.PullDirection = Vector3.zero;
				flock.HasPullDestination = false;
				flock.NextPullDestinationAt = 0f;
			}
			PlayerControllerB holder = flock.Holder;
			Vector3 position = ((Component)holder).transform.position;
			EnsureApparatusNav(flock, position);
			if (!flock.HasPullDestination || Time.time >= flock.NextPullDestinationAt || HorizontalDistance(position, flock.PullDestination) < 6f)
			{
				flock.NextPullDestinationAt = Time.time + 6f;
				Vector3 pullDestination = flock.PullDestination;
				bool hasPullDestination = flock.HasPullDestination;
				flock.HasPullDestination = TryChooseApparatusDestination(flock, position, 14f, 80f, pullDestination, hasPullDestination, out flock.PullDestination);
				flock.NextPullRouteAt = 0f;
				flock.PullRouteDirection = Vector3.zero;
			}
			Vector3 val = flock.PullRouteDirection;
			if (flock.HasPullDestination && flock.NavReady && flock.Nav.isOnNavMesh && Time.time >= flock.NextPullRouteAt)
			{
				flock.NextPullRouteAt = Time.time + 0.1f;
				NavMeshAgent nav = flock.Nav;
				NavMeshHit val2 = default(NavMeshHit);
				if (NavMesh.SamplePosition(position, ref val2, 3f, nav.areaMask))
				{
					nav.Warp(((NavMeshHit)(ref val2)).position);
				}
				val = Vector3.zero;
				if (nav.CalculatePath(flock.PullDestination, apparatusRoutePath) && (int)apparatusRoutePath.status != 2)
				{
					val = GetFirstMeaningfulPathDirection(apparatusRoutePath, position, 1.4f);
				}
				flock.PullRouteDirection = val;
			}
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f && flock.HasPullDestination)
			{
				val = flock.PullDestination - position;
				val.y = 0f;
			}
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				val = -((Component)holder).transform.forward;
				val.y = 0f;
			}
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				val = Vector3.forward;
			}
			((Vector3)(ref val)).Normalize();
			Vector3 pullDirection;
			if (!(((Vector3)(ref flock.PullDirection)).sqrMagnitude < 0.01f))
			{
				Vector3 val3 = Vector3.Slerp(flock.PullDirection, val, 1f - Mathf.Exp(-6f * Time.deltaTime));
				pullDirection = ((Vector3)(ref val3)).normalized;
			}
			else
			{
				pullDirection = val;
			}
			flock.PullDirection = pullDirection;
			OpenApparatusDoorsAhead(position + Vector3.up * 0.6f, flock.PullDirection, 3.6f);
			float num = Mathf.Clamp01((Time.time - flock.PullStartedAt) / 1.2f);
			num = num * num * (3f - 2f * num);
			float num2 = Mathf.Min(GetApparatusPullMagnitude(perched) * num, 4f);
			PublishApparatusPull(flock, flock.PullDirection * num2);
		}

		private static float GetApparatusPullMagnitude(int perched)
		{
			if (perched > 0)
			{
				return perched switch
				{
					1 => 0.7f, 
					2 => 1.2f, 
					3 => 1.9f, 
					4 => 2.5f, 
					_ => 3.1f, 
				};
			}
			return 0f;
		}

		private static void ClearApparatusPull(ApparatusFlock flock)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			flock.PullStartedAt = -1f;
			flock.PullDirection = Vector3.zero;
			flock.HasPullDestination = false;
			PublishApparatusPull(flock, Vector3.zero);
		}

		private static void PublishApparatusPull(ApparatusFlock flock, Vector3 pull)
		{
			//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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = flock.PublishedPull - pull;
			bool flag = ((Vector3)(ref val)).sqrMagnitude >= 0.0004f;
			flock.PublishedPull = pull;
			foreach (LightBatAI member in flock.Members)
			{
				if (!((Object)(object)member == (Object)null) && ((NetworkBehaviour)member).IsOwner && ((NetworkBehaviour)member).IsSpawned && (flag || !(member.syncedApparatusPull.Value == pull)))
				{
					member.syncedApparatusPull.Value = pull;
				}
			}
		}

		private void UpdateApparatusPlayerPull()
		{
			//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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			if (base.isEnemyDead || syncedApparatusPhase.Value != 2 || syncedApparatusPerchedCount.Value <= 0 || (Object)(object)GameNetworkManager.Instance == (Object)null)
			{
				return;
			}
			PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController;
			NetworkObject val = default(NetworkObject);
			if ((Object)(object)localPlayerController == (Object)null || localPlayerController.isPlayerDead || localPlayerController.inSpecialInteractAnimation || localPlayerController.isClimbingLadder || !TryGetSyncedApparatus(out LungProp apparatus) || !ApparatusIsPlayerHeld(apparatus) || (Object)(object)((GrabbableObject)apparatus).playerHeldBy != (Object)(object)localPlayerController || !((Component)apparatus).TryGetComponent<NetworkObject>(ref val))
			{
				return;
			}
			ulong networkObjectId = val.NetworkObjectId;
			int frameCount = Time.frameCount;
			if (!apparatusPullFrame.TryGetValue(networkObjectId, out var value) || value != frameCount)
			{
				apparatusPullFrame[networkObjectId] = frameCount;
				Vector3 val2 = syncedApparatusPull.Value;
				val2.y = 0f;
				bool airborne;
				float num = UpdateApparatusLift(localPlayerController, syncedApparatusPerchedCount.Value, val2, frameCount, out airborne);
				if (airborne)
				{
					val2 = Vector3.ClampMagnitude(val2 * 1.35f, 5.5f);
				}
				localPlayerController.externalForces += new Vector3(val2.x, num, val2.z);
			}
		}

		private static float UpdateApparatusLift(PlayerControllerB player, int perched, Vector3 pull, int frame, out bool airborne)
		{
			//IL_0049: 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_00a3: 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)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			airborne = false;
			if (perched < 4 || player.isInHangarShipRoom || player.isClimbingLadder || player.inSpecialInteractAnimation || player.isPlayerDead)
			{
				ReleaseApparatusLift(player);
				return 0f;
			}
			ulong playerClientId = player.playerClientId;
			Vector3 position = ((Component)player).transform.position;
			bool flag = false;
			if (!apparatusLiftStates.TryGetValue(playerClientId, out ApparatusLiftState value))
			{
				value = new ApparatusLiftState();
				apparatusLiftStates[playerClientId] = value;
				flag = true;
				EnsureApparatusHoldDriver();
			}
			else if (frame - value.TouchedFrame > 1)
			{
				flag = true;
				value.HoldingVertical = false;
				value.HasGround = false;
			}
			value.TouchedFrame = frame;
			float groundY;
			bool flag2 = TryFindApparatusLiftGround(position, out groundY);
			if (flag2)
			{
				value.GroundY = (value.HasGround ? Mathf.MoveTowards(value.GroundY, groundY, 3f * Time.deltaTime) : groundY);
				value.HasGround = true;
			}
			if (flag)
			{
				value.Height = (value.HasGround ? Mathf.Clamp(position.y - value.GroundY, 0f, 1.15f) : 0f);
			}
			float num;
			if (!flag2)
			{
				num = 0f;
			}
			else
			{
				float num2