Decompiled source of Defibrillator v1.0.0

Defibrillator.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LethalLib.Modules;
using Microsoft.CodeAnalysis;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Defibrillator")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Defibrillator")]
[assembly: AssemblyTitle("Defibrillator")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 DefibMod
{
	internal static class DefibFactory
	{
		private static readonly List<(Renderer renderer, Color color)> Parts = new List<(Renderer, Color)>();

		private static bool _assetsApplied;

		internal static AudioClip ShockClip;

		private static readonly Color CaseRed = new Color(0.78f, 0.08f, 0.08f);

		private static readonly Color Dark = new Color(0.1f, 0.1f, 0.11f);

		private static readonly Color ScreenGreen = new Color(0.1f, 0.45f, 0.2f);

		private static readonly Color White = new Color(0.95f, 0.95f, 0.95f);

		private static readonly Color PaddleYellow = new Color(0.95f, 0.75f, 0.1f);

		public static Item Create()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: 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_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: 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_0188: 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_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0409: Unknown result type (might be due to invalid IL or missing references)
			//IL_040e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0413: Unknown result type (might be due to invalid IL or missing references)
			//IL_0423: Unknown result type (might be due to invalid IL or missing references)
			//IL_0428: Unknown result type (might be due to invalid IL or missing references)
			//IL_042d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = NetworkPrefabs.CreateNetworkPrefab("DefibrillatorItem");
			val.layer = 6;
			val.tag = "PhysicsProp";
			MeshRenderer mainObjectRenderer = Part(val, "Case", new Vector3(0f, -0.17f, 0f), new Vector3(0.4f, 0.26f, 0.16f), CaseRed);
			Part(val, "Handle", new Vector3(0f, -0.005f, 0f), new Vector3(0.18f, 0.025f, 0.04f), Dark);
			Part(val, "HandlePostL", new Vector3(-0.08f, -0.025f, 0f), new Vector3(0.025f, 0.045f, 0.03f), Dark);
			Part(val, "HandlePostR", new Vector3(0.08f, -0.025f, 0f), new Vector3(0.025f, 0.045f, 0.03f), Dark);
			Part(val, "Screen", new Vector3(0.08f, -0.13f, 0.081f), new Vector3(0.15f, 0.08f, 0.005f), ScreenGreen);
			Part(val, "CrossH", new Vector3(-0.1f, -0.13f, 0.081f), new Vector3(0.08f, 0.022f, 0.005f), White);
			Part(val, "CrossV", new Vector3(-0.1f, -0.13f, 0.081f), new Vector3(0.022f, 0.08f, 0.005f), White);
			Part(val, "PaddleL", new Vector3(-0.09f, -0.24f, 0.095f), new Vector3(0.1f, 0.06f, 0.03f), PaddleYellow);
			Part(val, "PaddleR", new Vector3(0.09f, -0.24f, 0.095f), new Vector3(0.1f, 0.06f, 0.03f), PaddleYellow);
			BoxCollider obj = val.AddComponent<BoxCollider>();
			((Collider)obj).isTrigger = true;
			obj.center = new Vector3(0f, -0.16f, 0.02f);
			obj.size = new Vector3(0.42f, 0.32f, 0.22f);
			GameObject val2 = new GameObject("ScanNode")
			{
				layer = 22
			};
			val2.transform.SetParent(val.transform, false);
			val2.transform.localPosition = new Vector3(0f, -0.15f, 0f);
			BoxCollider obj2 = val2.AddComponent<BoxCollider>();
			((Collider)obj2).isTrigger = true;
			obj2.size = Vector3.one * 0.5f;
			ScanNodeProperties obj3 = val2.AddComponent<ScanNodeProperties>();
			obj3.headerText = "Defibrillator";
			obj3.subText = "Shock a teammate's body to revive them";
			obj3.nodeType = 0;
			obj3.minRange = 1;
			obj3.maxRange = 13;
			obj3.requiresLineOfSight = true;
			obj3.creatureScanID = -1;
			AudioSource val3 = val.AddComponent<AudioSource>();
			val3.playOnAwake = false;
			val3.spatialBlend = 1f;
			val3.rolloffMode = (AudioRolloffMode)1;
			val3.maxDistance = 25f;
			Item val4 = ScriptableObject.CreateInstance<Item>();
			((Object)val4).name = "DefibrillatorItem";
			val4.itemName = "Defibrillator";
			val4.creditsWorth = Plugin.Price.Value;
			val4.weight = 1f + Mathf.Max(0f, Plugin.WeightLbs.Value) / 105f;
			val4.isScrap = false;
			val4.twoHanded = false;
			val4.twoHandedAnimation = false;
			val4.holdButtonUse = false;
			val4.requiresBattery = true;
			val4.batteryUsage = 600f;
			val4.itemIsTrigger = false;
			val4.canBeGrabbedBeforeGameStart = true;
			val4.isConductiveMetal = true;
			val4.itemSpawnsOnGround = true;
			val4.allowDroppingAheadOfPlayer = true;
			val4.grabAnim = "";
			val4.verticalOffset = 0.3f;
			val4.restingRotation = Vector3.zero;
			val4.positionOffset = Plugin.ParseVec(Plugin.HoldPosition.Value, new Vector3(0f, 0.05f, 0f));
			val4.rotationOffset = Plugin.ParseVec(Plugin.HoldRotation.Value, Vector3.zero);
			val4.toolTips = new string[1] { "Shock body : [LMB]" };
			val4.spawnPositionTypes = new List<ItemGroup>();
			val4.meshVariants = (Mesh[])(object)new Mesh[0];
			val4.materialVariants = (Material[])(object)new Material[0];
			val4.highestSalePercentage = 80;
			val4.spawnPrefab = val;
			DefibrillatorItem defibrillatorItem = val.AddComponent<DefibrillatorItem>();
			((GrabbableObject)defibrillatorItem).itemProperties = val4;
			((GrabbableObject)defibrillatorItem).grabbable = true;
			((GrabbableObject)defibrillatorItem).grabbableToEnemies = true;
			((GrabbableObject)defibrillatorItem).mainObjectRenderer = mainObjectRenderer;
			defibrillatorItem.shockAudio = val3;
			return val4;
		}

		private static MeshRenderer Part(GameObject parent, string name, Vector3 pos, Vector3 size, Color color)
		{
			//IL_0037: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3);
			Object.DestroyImmediate((Object)(object)obj.GetComponent<Collider>());
			((Object)obj).name = name;
			obj.layer = 6;
			obj.transform.SetParent(parent.transform, false);
			obj.transform.localPosition = pos;
			obj.transform.localScale = size;
			MeshRenderer component = obj.GetComponent<MeshRenderer>();
			Parts.Add(((Renderer)(object)component, color));
			return component;
		}

		public static void ApplyVanillaAssets()
		{
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Expected O, but got Unknown
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			if (_assetsApplied || (Object)(object)StartOfRound.Instance == (Object)null)
			{
				return;
			}
			try
			{
				List<Item> vanilla = StartOfRound.Instance.allItemsList.itemsList;
				Material val = null;
				foreach (Item item3 in vanilla)
				{
					if (!((Object)(object)item3 == (Object)null) && !((Object)(object)item3.spawnPrefab == (Object)null) && !((Object)(object)item3 == (Object)(object)Plugin.DefibItem))
					{
						MeshRenderer componentInChildren = item3.spawnPrefab.GetComponentInChildren<MeshRenderer>(true);
						if ((Object)(object)componentInChildren != (Object)null && (Object)(object)((Renderer)componentInChildren).sharedMaterial != (Object)null && ((Renderer)componentInChildren).sharedMaterial.HasProperty("_BaseColor"))
						{
							val = ((Renderer)componentInChildren).sharedMaterial;
							break;
						}
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					foreach (var part in Parts)
					{
						Renderer item = part.renderer;
						Color item2 = part.color;
						Material val2 = new Material(val)
						{
							name = "Defib_" + ((Object)item).name
						};
						string[] array = new string[4] { "_BaseColorMap", "_NormalMap", "_MaskMap", "_EmissiveColorMap" };
						foreach (string text in array)
						{
							if (val2.HasProperty(text))
							{
								val2.SetTexture(text, (Texture)null);
							}
						}
						val2.DisableKeyword("_NORMALMAP");
						val2.DisableKeyword("_MASKMAP");
						val2.SetColor("_BaseColor", item2);
						if (val2.HasProperty("_Metallic"))
						{
							val2.SetFloat("_Metallic", 0.1f);
						}
						if (val2.HasProperty("_Smoothness"))
						{
							val2.SetFloat("_Smoothness", 0.45f);
						}
						item.sharedMaterial = val2;
					}
				}
				else
				{
					Plugin.Log.LogWarning((object)"Couldn't find a vanilla material to copy; the defibrillator may look pink.");
				}
				Item val3 = new string[4] { "Zap gun", "Pro-flashlight", "Flashlight", "Walkie-talkie" }.Select((string n) => ((IEnumerable<Item>)vanilla).FirstOrDefault((Func<Item, bool>)((Item val4) => (Object)(object)val4 != (Object)null && val4.itemName == n))).FirstOrDefault<Item>((Func<Item, bool>)((Item val4) => (Object)(object)val4 != (Object)null));
				if ((Object)(object)val3 != (Object)null)
				{
					Plugin.DefibItem.itemIcon = val3.itemIcon;
					Plugin.DefibItem.grabSFX = val3.grabSFX;
					Plugin.DefibItem.dropSFX = val3.dropSFX;
					Plugin.DefibItem.pocketSFX = val3.pocketSFX;
				}
				_assetsApplied = true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Failed to apply vanilla assets: " + ex));
			}
		}

		public static AudioClip GetShockClip()
		{
			if ((Object)(object)ShockClip != (Object)null)
			{
				return ShockClip;
			}
			try
			{
				ItemCharger val = Object.FindObjectOfType<ItemCharger>();
				if ((Object)(object)val != (Object)null)
				{
					object value = Traverse.Create((object)val).Field("zapAudio").GetValue();
					AudioSource val2 = (AudioSource)((value is AudioSource) ? value : null);
					if (val2 != null && (Object)(object)val2.clip != (Object)null)
					{
						return ShockClip = val2.clip;
					}
				}
				ShockClip = ((IEnumerable<AudioClip>)Resources.FindObjectsOfTypeAll<AudioClip>()).FirstOrDefault((Func<AudioClip, bool>)((AudioClip c) => ((Object)c).name.IndexOf("zap", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)c).name.IndexOf("shock", StringComparison.OrdinalIgnoreCase) >= 0));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("No shock clip: " + ex.Message));
			}
			return ShockClip;
		}
	}
	public class DefibrillatorItem : GrabbableObject
	{
		public AudioSource shockAudio;

		private bool _charging;

		private float _nextUseTime;

		private static float ShockCost => 1f / (float)Mathf.Max(1, Plugin.ShocksPerBattery.Value);

		public override void ItemActivate(bool used, bool buttonDown = true)
		{
			((GrabbableObject)this).ItemActivate(used, buttonDown);
			PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController;
			if (buttonDown && !((Object)(object)base.playerHeldBy == (Object)null) && !((Object)(object)base.playerHeldBy != (Object)(object)localPlayerController) && !_charging && !(Time.time < _nextUseTime))
			{
				PlayerControllerB val = ReviveNetwork.FindRevivableBody(localPlayerController, Plugin.Range.Value);
				if ((Object)(object)val == (Object)null)
				{
					_nextUseTime = Time.time + 1f;
					HUDManager.Instance.DisplayTip("Defibrillator", "No body in range. Stand right next to a dead teammate.", false, false, "LC_Tip1");
				}
				else if (base.insertedBattery == null || base.insertedBattery.charge + 0.001f < ShockCost)
				{
					_nextUseTime = Time.time + 1f;
					HUDManager.Instance.DisplayTip("Defibrillator", "Battery too low. Charge it at the ship.", true, false, "LC_Tip1");
				}
				else
				{
					((MonoBehaviour)this).StartCoroutine(ChargeAndShock(val));
				}
			}
		}

		private IEnumerator ChargeAndShock(PlayerControllerB target)
		{
			_charging = true;
			PlayerControllerB holder = base.playerHeldBy;
			yield return (object)new WaitForSeconds(Mathf.Max(0f, Plugin.ChargeUpTime.Value));
			_charging = false;
			_nextUseTime = Time.time + 1f;
			if ((Object)(object)base.playerHeldBy == (Object)null || (Object)(object)base.playerHeldBy != (Object)(object)holder || base.isPocketed || holder.isPlayerDead)
			{
				yield break;
			}
			if (!ReviveNetwork.IsRevivable(target, holder, Plugin.Range.Value + 0.75f))
			{
				HUDManager.Instance.DisplayTip("Defibrillator", "Lost contact with the body.", false, false, "LC_Tip1");
				yield break;
			}
			base.insertedBattery.charge = Mathf.Max(0f, base.insertedBattery.charge - ShockCost);
			if (base.insertedBattery.charge <= 0.001f)
			{
				base.insertedBattery.empty = true;
			}
			((GrabbableObject)this).SyncBatteryServerRpc((int)(base.insertedBattery.charge * 100f));
			ReviveNetwork.RequestRevive(target, holder);
		}

		public void PlayShockEffects()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			AudioClip shockClip = DefibFactory.GetShockClip();
			if ((Object)(object)shockClip != (Object)null && (Object)(object)shockAudio != (Object)null)
			{
				shockAudio.PlayOneShot(shockClip, 1f);
			}
			if ((Object)(object)RoundManager.Instance != (Object)null)
			{
				RoundManager.Instance.PlayAudibleNoise(((Component)this).transform.position, 15f, 0.8f, 0, base.isInShipRoom, 0);
			}
		}
	}
	[BepInPlugin("markj.defibrillator", "Defibrillator", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "markj.defibrillator";

		public const string Name = "Defibrillator";

		public const string Version = "1.0.0";

		internal static ManualLogSource Log;

		internal static Item DefibItem;

		internal static ConfigEntry<int> Price;

		internal static ConfigEntry<int> ShocksPerBattery;

		internal static ConfigEntry<int> ReviveHealth;

		internal static ConfigEntry<float> Range;

		internal static ConfigEntry<float> ChargeUpTime;

		internal static ConfigEntry<float> WeightLbs;

		internal static ConfigEntry<string> HoldPosition;

		internal static ConfigEntry<string> HoldRotation;

		private void Awake()
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Price = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Price", 250, "Store price in credits. Everyone in the lobby should use the same value.");
			ShocksPerBattery = ((BaseUnityPlugin)this).Config.Bind<int>("General", "ShocksPerBattery", 3, "Revives per full battery. Recharge it at the ship's charging station.");
			ReviveHealth = ((BaseUnityPlugin)this).Config.Bind<int>("General", "ReviveHealth", 50, new ConfigDescription("Health a revived player comes back with.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
			Range = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Range", 2.5f, "How close (in metres) you need to be to a body.");
			ChargeUpTime = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ChargeUpTime", 1.5f, "Seconds between pressing use and the shock. Stay near the body while it charges.");
			WeightLbs = ((BaseUnityPlugin)this).Config.Bind<float>("General", "WeightLbs", 12f, "Item weight in pounds.");
			HoldPosition = ((BaseUnityPlugin)this).Config.Bind<string>("Visuals", "HoldPosition", "0,0.05,0", "x,y,z offset of the model in your hand. Tweak if it looks off.");
			HoldRotation = ((BaseUnityPlugin)this).Config.Bind<string>("Visuals", "HoldRotation", "0,0,0", "x,y,z rotation of the model in your hand. Tweak if it looks off.");
			DefibItem = DefibFactory.Create();
			Items.RegisterShopItem(DefibItem, Price.Value);
			new Harmony("markj.defibrillator").PatchAll(typeof(Patches));
			Log.LogInfo((object)"Defibrillator 1.0.0 loaded.");
		}

		internal static Vector3 ParseVec(string s, Vector3 fallback)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			string[] array = s.Split(',');
			if (array.Length == 3 && float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3))
			{
				return new Vector3(result, result2, result3);
			}
			return fallback;
		}
	}
	[HarmonyPatch]
	internal static class Patches
	{
		[HarmonyPatch(typeof(StartOfRound), "Awake")]
		[HarmonyPostfix]
		private static void StartOfRoundAwake()
		{
			DefibFactory.ApplyVanillaAssets();
		}

		[HarmonyPatch(typeof(StartOfRound), "Start")]
		[HarmonyPostfix]
		private static void StartOfRoundStart()
		{
			ReviveNetwork.Register();
		}
	}
	internal static class ReviveNetwork
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__OnRequestRevive;

			public static HandleNamedMessageDelegate <1>__OnDoRevive;
		}

		private const string RequestMsg = "Defibrillator_RequestRevive";

		private const string ReviveMsg = "Defibrillator_DoRevive";

		public static void Register()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			//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_0073: Expected O, but got Unknown
			NetworkManager singleton = NetworkManager.Singleton;
			CustomMessagingManager val = ((singleton != null) ? singleton.CustomMessagingManager : null);
			if (val != null)
			{
				val.UnregisterNamedMessageHandler("Defibrillator_RequestRevive");
				val.UnregisterNamedMessageHandler("Defibrillator_DoRevive");
				object obj = <>O.<0>__OnRequestRevive;
				if (obj == null)
				{
					HandleNamedMessageDelegate val2 = OnRequestRevive;
					<>O.<0>__OnRequestRevive = val2;
					obj = (object)val2;
				}
				val.RegisterNamedMessageHandler("Defibrillator_RequestRevive", (HandleNamedMessageDelegate)obj);
				object obj2 = <>O.<1>__OnDoRevive;
				if (obj2 == null)
				{
					HandleNamedMessageDelegate val3 = OnDoRevive;
					<>O.<1>__OnDoRevive = val3;
					obj2 = (object)val3;
				}
				val.RegisterNamedMessageHandler("Defibrillator_DoRevive", (HandleNamedMessageDelegate)obj2);
			}
		}

		public static PlayerControllerB FindRevivableBody(PlayerControllerB reviver, float range)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB result = null;
			float num = float.MaxValue;
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (IsRevivable(val, reviver, range))
				{
					float num2 = Vector3.Distance(ClosestBodyPoint(val.deadBody, ((Component)reviver).transform.position), ((Component)reviver).transform.position);
					if (num2 < num)
					{
						num = num2;
						result = val;
					}
				}
			}
			return result;
		}

		public static bool IsRevivable(PlayerControllerB p, PlayerControllerB reviver, float range)
		{
			//IL_007a: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)p == (Object)null || (Object)(object)reviver == (Object)null || (Object)(object)p == (Object)(object)reviver)
			{
				return false;
			}
			if (!p.isPlayerDead || p.disconnectedMidGame)
			{
				return false;
			}
			DeadBodyInfo deadBody = p.deadBody;
			if ((Object)(object)deadBody == (Object)null || deadBody.deactivated || !((Component)deadBody).gameObject.activeInHierarchy)
			{
				return false;
			}
			if ((Object)(object)deadBody.grabBodyObject != (Object)null && deadBody.grabBodyObject.isHeld)
			{
				return false;
			}
			return Vector3.Distance(ClosestBodyPoint(deadBody, ((Component)reviver).transform.position), ((Component)reviver).transform.position) <= range;
		}

		private static Vector3 ClosestBodyPoint(DeadBodyInfo body, Vector3 from)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			if (body.bodyParts == null || body.bodyParts.Length == 0)
			{
				return ((Component)body).transform.position;
			}
			return (from b in body.bodyParts
				where (Object)(object)b != (Object)null
				select ((Component)b).transform.position).OrderBy(delegate(Vector3 pos)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: 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)
				Vector3 val = pos - from;
				return ((Vector3)(ref val)).sqrMagnitude;
			}).DefaultIfEmpty(((Component)body).transform.position).First();
		}

		public unsafe static void RequestRevive(PlayerControllerB target, PlayerControllerB reviver)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager singleton = NetworkManager.Singleton;
			if (singleton.IsServer)
			{
				ServerHandleRequest((int)target.playerClientId, (int)reviver.playerClientId, singleton.LocalClientId);
				return;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(16, (Allocator)2, -1);
			try
			{
				int num = (int)target.playerClientId;
				((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
				num = (int)reviver.playerClientId;
				((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
				singleton.CustomMessagingManager.SendNamedMessage("Defibrillator_RequestRevive", 0uL, val, (NetworkDelivery)2);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private static void OnRequestRevive(ulong sender, FastBufferReader r)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkManager.Singleton.IsServer)
			{
				int targetId = default(int);
				((FastBufferReader)(ref r)).ReadValueSafe<int>(ref targetId, default(ForPrimitives));
				int reviverId = default(int);
				((FastBufferReader)(ref r)).ReadValueSafe<int>(ref reviverId, default(ForPrimitives));
				ServerHandleRequest(targetId, reviverId, sender);
			}
		}

		private unsafe static void ServerHandleRequest(int targetId, int reviverId, ulong sender)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: 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_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: 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_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: 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_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			if (targetId < 0 || targetId >= allPlayerScripts.Length || reviverId < 0 || reviverId >= allPlayerScripts.Length)
			{
				return;
			}
			PlayerControllerB val = allPlayerScripts[targetId];
			PlayerControllerB val2 = allPlayerScripts[reviverId];
			if (val2.actualClientId != sender || val2.isPlayerDead || !val2.isPlayerControlled || !IsRevivable(val, val2, Plugin.Range.Value + 3f))
			{
				return;
			}
			Vector3 pos = ClosestBodyPoint(val.deadBody, ((Component)val2).transform.position) + Vector3.up * 0.5f;
			int health = Mathf.Clamp(Plugin.ReviveHealth.Value, 1, 100);
			GrabbableObject grabBodyObject = val.deadBody.grabBodyObject;
			List<ulong> list = NetworkManager.Singleton.ConnectedClientsIds.Where((ulong id) => id != 0).ToList();
			if (list.Count > 0)
			{
				FastBufferWriter val3 = default(FastBufferWriter);
				((FastBufferWriter)(ref val3))..ctor(32, (Allocator)2, -1);
				try
				{
					((FastBufferWriter)(ref val3)).WriteValueSafe<int>(ref targetId, default(ForPrimitives));
					((FastBufferWriter)(ref val3)).WriteValueSafe<int>(ref reviverId, default(ForPrimitives));
					((FastBufferWriter)(ref val3)).WriteValueSafe<float>(ref pos.x, default(ForPrimitives));
					((FastBufferWriter)(ref val3)).WriteValueSafe<float>(ref pos.y, default(ForPrimitives));
					((FastBufferWriter)(ref val3)).WriteValueSafe<float>(ref pos.z, default(ForPrimitives));
					((FastBufferWriter)(ref val3)).WriteValueSafe<int>(ref health, default(ForPrimitives));
					NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("Defibrillator_DoRevive", (IReadOnlyList<ulong>)list, val3, (NetworkDelivery)2);
				}
				finally
				{
					((IDisposable)(*(FastBufferWriter*)(&val3))/*cast due to .constrained prefix*/).Dispose();
				}
			}
			DoRevive(val, val2, pos, health);
			if ((Object)(object)grabBodyObject != (Object)null && (Object)(object)((NetworkBehaviour)grabBodyObject).NetworkObject != (Object)null && ((NetworkBehaviour)grabBodyObject).NetworkObject.IsSpawned)
			{
				((NetworkBehaviour)grabBodyObject).NetworkObject.Despawn(true);
			}
		}

		private static void OnDoRevive(ulong sender, FastBufferReader r)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_0069: 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)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			if (sender == 0L)
			{
				int num = default(int);
				((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num, default(ForPrimitives));
				int num2 = default(int);
				((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num2, default(ForPrimitives));
				float num3 = default(float);
				((FastBufferReader)(ref r)).ReadValueSafe<float>(ref num3, default(ForPrimitives));
				float num4 = default(float);
				((FastBufferReader)(ref r)).ReadValueSafe<float>(ref num4, default(ForPrimitives));
				float num5 = default(float);
				((FastBufferReader)(ref r)).ReadValueSafe<float>(ref num5, default(ForPrimitives));
				int health = default(int);
				((FastBufferReader)(ref r)).ReadValueSafe<int>(ref health, default(ForPrimitives));
				PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
				if (num >= 0 && num < allPlayerScripts.Length && num2 >= 0 && num2 < allPlayerScripts.Length)
				{
					DoRevive(allPlayerScripts[num], allPlayerScripts[num2], new Vector3(num3, num4, num5), health);
				}
			}
		}

		private static void DoRevive(PlayerControllerB p, PlayerControllerB reviver, Vector3 pos, int health)
		{
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)p == (Object)null || !p.isPlayerDead)
			{
				return;
			}
			StartOfRound instance = StartOfRound.Instance;
			bool flag = (Object)(object)p == (Object)(object)GameNetworkManager.Instance.localPlayerController;
			int num = (int)p.playerClientId;
			Plugin.Log.LogInfo((object)(reviver?.playerUsername + " revived " + p.playerUsername));
			try
			{
				if ((Object)(object)p.deadBody != (Object)null)
				{
					try
					{
						p.deadBody.DeactivateBody(false);
					}
					catch (Exception ex)
					{
						Plugin.Log.LogWarning((object)ex.Message);
					}
					p.deadBody = null;
				}
				R.Call(p, "ResetPlayerBloodObjects", true);
				p.isClimbingLadder = false;
				p.clampLooking = false;
				p.disableMoveInput = false;
				p.disableLookInput = false;
				R.Set(p, "disableInteract", false);
				R.Set(p, "inVehicleAnimation", false);
				p.ResetZAndXRotation();
				((Collider)p.thisController).enabled = true;
				p.health = health;
				p.hasBeenCriticallyInjured = false;
				p.isPlayerDead = false;
				p.isPlayerControlled = true;
				if ((Object)(object)reviver != (Object)null)
				{
					p.isInElevator = reviver.isInElevator;
					p.isInHangarShipRoom = reviver.isInHangarShipRoom;
					p.isInsideFactory = reviver.isInsideFactory;
				}
				R.Set(p, "parentedToElevatorLastFrame", false);
				R.Set(p, "overrideGameOverSpectatePivot", null);
				R.Call(instance, "SetPlayerObjectExtrapolate", false);
				p.TeleportPlayer(pos, false, 0f, false, true);
				R.Set(p, "setPositionOfDeadPlayer", false);
				p.DisablePlayerModel(((Component)p).gameObject, true, true);
				if (flag)
				{
					((Renderer)p.thisPlayerModelArms).enabled = true;
				}
				if ((Object)(object)p.helmetLight != (Object)null)
				{
					((Behaviour)p.helmetLight).enabled = false;
				}
				p.Crouch(false);
				p.criticallyInjured = health < 20;
				p.bleedingHeavily = false;
				if ((Object)(object)p.playerBodyAnimator != (Object)null)
				{
					p.playerBodyAnimator.SetBool("Limp", p.criticallyInjured);
				}
				p.activatingItem = false;
				p.twoHanded = false;
				p.inShockingMinigame = false;
				p.inSpecialInteractAnimation = false;
				p.inAnimationWithEnemy = null;
				p.holdingWalkieTalkie = false;
				p.speakingToWalkieTalkie = false;
				R.Set(p, "freeRotationInInteractAnimation", false);
				R.Set(p, "disableSyncInAnimation", false);
				R.Set(p, "isSinking", false);
				R.Set(p, "isUnderwater", false);
				R.Set(p, "sinkingValue", 0f);
				R.Set(p, "externalForceAutoFade", Vector3.zero);
				R.Set(p, "causeOfDeath", (object)(CauseOfDeath)0);
				if ((Object)(object)p.statusEffectAudio != (Object)null)
				{
					p.statusEffectAudio.Stop();
				}
				R.Call(p, "DisableJetpackControlsLocally");
				if ((Object)(object)p.mapRadarDotAnimator != (Object)null)
				{
					p.mapRadarDotAnimator.SetBool("dead", false);
				}
				p.voiceMuffledByEnemy = false;
				if (flag)
				{
					ReviveLocalView(p, health);
				}
				if ((Object)(object)SoundManager.Instance != (Object)null && num < SoundManager.Instance.playerVoicePitchTargets.Length)
				{
					SoundManager.Instance.playerVoicePitchTargets[num] = 1f;
					SoundManager.Instance.SetPlayerPitch(1f, num);
				}
				instance.livingPlayers = Mathf.Min(instance.livingPlayers + 1, instance.connectedPlayersAmount + 1);
				instance.allPlayersDead = false;
				instance.UpdatePlayerVoiceEffects();
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogError((object)("Revive failed partway: " + ex2));
			}
			if ((Object)(object)reviver != (Object)null && reviver.currentlyHeldObjectServer is DefibrillatorItem defibrillatorItem)
			{
				defibrillatorItem.PlayShockEffects();
			}
		}

		private static void ReviveLocalView(PlayerControllerB p, int health)
		{
			HUDManager instance = HUDManager.Instance;
			StartOfRound instance2 = StartOfRound.Instance;
			R.Set(p, "hasBegunSpectating", false);
			p.spectatedPlayerScript = null;
			R.Set(p, "hinderedMultiplier", 1f);
			R.Set(p, "isMovementHindered", 0);
			R.Set(p, "sourcesCausingSinking", 0);
			R.Call(instance, "RemoveSpectateUI");
			object obj = R.Get(instance, "gameOverAnimator");
			object obj2 = ((obj is Animator) ? obj : null);
			if (obj2 != null)
			{
				((Animator)obj2).SetTrigger("revive");
			}
			object obj3 = R.Get(instance, "gasHelmetAnimator");
			object obj4 = ((obj3 is Animator) ? obj3 : null);
			if (obj4 != null)
			{
				((Animator)obj4).SetBool("gasEmitting", false);
			}
			object obj5 = R.Get(instance, "audioListenerLowPass");
			Behaviour val = (Behaviour)((obj5 is Behaviour) ? obj5 : null);
			if (val != null)
			{
				val.enabled = false;
			}
			R.Call(instance2, "SetSpectateCameraToGameOverMode", false, p);
			instance2.SwitchCamera(p.gameplayCamera);
			R.Call(p, "ChangeAudioListenerToObject", ((Component)p.gameplayCamera).gameObject);
			R.Call(instance, "HideHUD", false);
			instance.UpdateHealthUI(health, false);
			R.Set(SoundManager.Instance, "earsRingingTimer", 0f);
			instance.DisplayTip("Revived", "A teammate shocked you back to life!", false, false, "LC_Tip1");
		}
	}
	internal static class R
	{
		private static readonly HashSet<string> Warned = new HashSet<string>();

		private static void Warn(string what)
		{
			if (Warned.Add(what))
			{
				Plugin.Log.LogWarning((object)("Game member not found (game version difference?): " + what));
			}
		}

		public static object Get(object obj, string name)
		{
			if (obj == null)
			{
				return null;
			}
			FieldInfo fieldInfo = AccessTools.Field(obj.GetType(), name);
			if (fieldInfo != null)
			{
				return fieldInfo.GetValue(obj);
			}
			PropertyInfo propertyInfo = AccessTools.Property(obj.GetType(), name);
			if (propertyInfo != null && propertyInfo.CanRead)
			{
				return propertyInfo.GetValue(obj);
			}
			Warn(obj.GetType().Name + "." + name);
			return null;
		}

		public static void Set(object obj, string name, object value)
		{
			if (obj == null)
			{
				return;
			}
			try
			{
				FieldInfo fieldInfo = AccessTools.Field(obj.GetType(), name);
				if (fieldInfo != null)
				{
					fieldInfo.SetValue(obj, value);
					return;
				}
				PropertyInfo propertyInfo = AccessTools.Property(obj.GetType(), name);
				if (propertyInfo != null && propertyInfo.CanWrite)
				{
					propertyInfo.SetValue(obj, value);
				}
				else
				{
					Warn(obj.GetType().Name + "." + name);
				}
			}
			catch (Exception ex)
			{
				Warn(obj.GetType().Name + "." + name + " (" + ex.Message + ")");
			}
		}

		public static void Call(object obj, string name, params object[] args)
		{
			if (obj == null)
			{
				return;
			}
			try
			{
				List<MethodInfo> declaredMethods = AccessTools.GetDeclaredMethods(obj.GetType());
				IEnumerable<MethodInfo> second;
				if (!(obj.GetType().BaseType != null))
				{
					second = Enumerable.Empty<MethodInfo>();
				}
				else
				{
					IEnumerable<MethodInfo> declaredMethods2 = AccessTools.GetDeclaredMethods(obj.GetType().BaseType);
					second = declaredMethods2;
				}
				MethodInfo methodInfo = declaredMethods.Concat(second).FirstOrDefault((MethodInfo m) => m.Name == name && m.GetParameters().Length >= args.Length && m.GetParameters().Skip(args.Length).All((ParameterInfo pi) => pi.HasDefaultValue));
				if (methodInfo == null)
				{
					Warn(obj.GetType().Name + "." + name + "()");
					return;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				object[] array = new object[parameters.Length];
				for (int num = 0; num < parameters.Length; num++)
				{
					array[num] = ((num < args.Length) ? args[num] : parameters[num].DefaultValue);
				}
				methodInfo.Invoke(obj, array);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)(obj.GetType().Name + "." + name + "() threw: " + (ex.InnerException?.Message ?? ex.Message)));
			}
		}
	}
}