Decompiled source of Industrial Defibrillator v0.1.5

BepInEx/plugins/IndustrialDefibrillator/Defibrillator.Core.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using Microsoft.CodeAnalysis;

[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.Core")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.5.0")]
[assembly: AssemblyInformationalVersion("0.1.5+9d197fcbfb4d444b476161ad58b79e319e14f80f")]
[assembly: AssemblyProduct("Defibrillator.Core")]
[assembly: AssemblyTitle("Defibrillator.Core")]
[assembly: AssemblyVersion("0.1.5.0")]
[module: RefSafetyRules(11)]
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 Defibrillator.Core
{
	public static class AftershockImpact
	{
		public static bool RollTumble(double sample, double chance)
		{
			if (!Settings.Finite(sample) || sample < 0.0 || sample >= 1.0)
			{
				throw new ArgumentOutOfRangeException("sample");
			}
			if (!Settings.Finite(chance) || chance < 0.0 || chance > 1.0)
			{
				throw new ArgumentOutOfRangeException("chance");
			}
			return sample < chance;
		}

		public static float YawAt(float degrees, double progress)
		{
			if (!Settings.Finite(degrees) || Math.Abs(degrees) > 180f)
			{
				throw new ArgumentOutOfRangeException("degrees");
			}
			if (!Settings.Finite(progress))
			{
				throw new ArgumentOutOfRangeException("progress");
			}
			double num = Math.Max(0.0, Math.Min(1.0, progress));
			return (float)((double)degrees * num * num * (3.0 - 2.0 * num));
		}

		public static (float Strength, float Seconds) UpgradeLegacy(int revision, float strength, float seconds)
		{
			if (revision < 1)
			{
				return (Strength: (strength == 3.5f) ? 7f : strength, Seconds: (seconds == 0.8f) ? 1.2f : seconds);
			}
			return (Strength: strength, Seconds: seconds);
		}
	}
	public static class BalanceMigration
	{
		public const int Revision = 1;

		public const int Price = 2;

		public const int BatteryCost = 50;

		public static (int Price, int BatteryCost) Apply(int revision, int price, int batteryCost)
		{
			if (revision >= 1)
			{
				return (Price: price, BatteryCost: batteryCost);
			}
			return (Price: (price == 0) ? 2 : price, BatteryCost: (batteryCost == 25) ? 50 : batteryCost);
		}
	}
	public static class DeviceGeometry
	{
		public const float ModelScale = 0.5f;

		public const float MassKg = 3f;

		public const float FloorY = -0.07875f;

		public static IReadOnlyList<CollisionBox> CollisionBoxes { get; } = Array.AsReadOnly(new CollisionBox[6]
		{
			new CollisionBox("Casing", 0f, 0f, 0f, 0.51f, 0.315f, 0.24f),
			new CollisionBox("Left paddle", -0.3f, 0f, -0.025f, 0.1f, 0.16f, 0.12f),
			new CollisionBox("Right paddle", 0.3f, 0f, -0.025f, 0.1f, 0.16f, 0.12f),
			new CollisionBox("Handle", 0f, 0.23f, 0f, 0.22f, 0.032f, 0.05f),
			new CollisionBox("Left handle mount", -0.11f, 0.19f, 0f, 0.025f, 0.08f, 0.05f),
			new CollisionBox("Right handle mount", 0.11f, 0.19f, 0f, 0.025f, 0.08f, 0.05f)
		});
	}
	public readonly struct CollisionBox
	{
		public string Name { get; }

		public float X { get; }

		public float Y { get; }

		public float Z { get; }

		public float Width { get; }

		public float Height { get; }

		public float Depth { get; }

		internal CollisionBox(string name, float x, float y, float z, float width, float height, float depth)
		{
			Name = name;
			X = x;
			Y = y;
			Z = z;
			Width = width;
			Height = height;
			Depth = depth;
		}
	}
	[Flags]
	public enum DonorParts
	{
		None = 0,
		Tracker = 1,
		Attributes = 2,
		Battery = 4,
		Equippable = 8,
		Physics = 0x10,
		Rigidbody = 0x20,
		NetworkView = 0x40,
		ColorPreset = 0x80,
		BatteryDisplay = 0x100,
		NativeReviver = 0x200
	}
	public static class DonorRequirements
	{
		public const DonorParts Required = DonorParts.Tracker | DonorParts.Attributes | DonorParts.Battery | DonorParts.Equippable | DonorParts.Physics | DonorParts.Rigidbody | DonorParts.NetworkView | DonorParts.ColorPreset;

		public static DonorParts Missing(DonorParts available)
		{
			return (DonorParts.Tracker | DonorParts.Attributes | DonorParts.Battery | DonorParts.Equippable | DonorParts.Physics | DonorParts.Rigidbody | DonorParts.NetworkView | DonorParts.ColorPreset) & ~available;
		}

		public static bool IsCompatible(DonorParts available)
		{
			if (Missing(available) == DonorParts.None)
			{
				return (available & DonorParts.NativeReviver) == 0;
			}
			return false;
		}
	}
	public sealed class PcmWave
	{
		public int SampleRate { get; }

		public float[] Samples { get; }

		public double Seconds => (double)Samples.Length / (double)SampleRate;

		private PcmWave(int rate, float[] samples)
		{
			SampleRate = rate;
			Samples = samples;
		}

		public static PcmWave Read(Stream input)
		{
			using MemoryStream memoryStream = new MemoryStream();
			byte[] array = new byte[4096];
			int count;
			while ((count = input.Read(array, 0, array.Length)) > 0)
			{
				memoryStream.Write(array, 0, count);
				if (memoryStream.Length > 400000)
				{
					throw new InvalidDataException("Animal WAV exceeds size limit.");
				}
			}
			memoryStream.Position = 0L;
			BinaryReader reader = new BinaryReader(memoryStream, Encoding.ASCII, leaveOpen: true);
			try
			{
				if (memoryStream.Length < 44 || Four() != "RIFF")
				{
					throw new InvalidDataException("Expected RIFF WAV.");
				}
				if ((long)reader.ReadUInt32() + 8L != memoryStream.Length || Four() != "WAVE")
				{
					throw new InvalidDataException("Invalid WAV container.");
				}
				int num = 0;
				bool flag = false;
				byte[] array2 = null;
				while (memoryStream.Position + 8 <= memoryStream.Length)
				{
					string text = Four();
					uint num2 = reader.ReadUInt32();
					long num3 = memoryStream.Position + num2;
					if (num3 > memoryStream.Length)
					{
						throw new InvalidDataException("Truncated WAV chunk.");
					}
					if (text == "fmt ")
					{
						if (flag || num2 < 16 || reader.ReadUInt16() != 1 || reader.ReadUInt16() != 1)
						{
							throw new InvalidDataException("Expected mono PCM.");
						}
						num = reader.ReadInt32();
						int num4 = reader.ReadInt32();
						int num5 = reader.ReadUInt16();
						int num6 = reader.ReadUInt16();
						if ((num != 44100 && num != 48000) || num6 != 16 || num5 != 2 || num4 != num * 2)
						{
							throw new InvalidDataException("Expected PCM16 at 44100/48000 Hz.");
						}
						flag = true;
					}
					else if (text == "data")
					{
						if (array2 != null || num2 == 0 || num2 % 2 != 0)
						{
							throw new InvalidDataException("Invalid PCM data.");
						}
						array2 = reader.ReadBytes((int)num2);
					}
					memoryStream.Position = num3 + num2 % 2;
					if (memoryStream.Position > memoryStream.Length)
					{
						throw new InvalidDataException("Missing WAV padding.");
					}
				}
				if (!flag || array2 == null || array2.Length / 2 > num * 3)
				{
					throw new InvalidDataException("Missing audio or clip exceeds three seconds.");
				}
				float[] array3 = new float[array2.Length / 2];
				for (int i = 0; i < array3.Length; i++)
				{
					array3[i] = (float)(short)(array2[2 * i] | (array2[2 * i + 1] << 8)) / 32768f;
				}
				return new PcmWave(num, array3);
			}
			finally
			{
				if (reader != null)
				{
					((IDisposable)reader).Dispose();
				}
			}
			string Four()
			{
				return Encoding.ASCII.GetString(reader.ReadBytes(4));
			}
		}
	}
	public enum Outcome
	{
		Charging,
		Revived,
		Cancelled,
		InvalidRequest,
		InvalidTarget,
		ItemUnavailable,
		Busy,
		EmptyBattery,
		Interrupted,
		TimedOut,
		RevivalFailed
	}
	public readonly struct Result
	{
		public Outcome Outcome { get; }

		public double Progress { get; }

		public int Charge { get; }

		internal Result(Outcome outcome, double progress, int charge)
		{
			Outcome = outcome;
			Progress = progress;
			Charge = charge;
		}
	}
	public sealed class RevivalService
	{
		private sealed class ItemState
		{
			public int Charge;

			public Session? Session;

			public ItemState(int charge)
			{
				Charge = charge;
			}
		}

		private sealed class Session
		{
			public int Actor;

			public int Target;

			public string Life = "";

			public long Damage;

			public double Started;

			public double LastHeartbeat;
		}

		private readonly Settings settings;

		private readonly IRevivalWorld world;

		private readonly Func<double> clock;

		private readonly Dictionary<string, ItemState> items = new Dictionary<string, ItemState>();

		private readonly HashSet<string> completedLives = new HashSet<string>();

		private double lastTime = double.NegativeInfinity;

		private bool inCommit;

		public RevivalService(Settings settings, IRevivalWorld world, Func<double> monotonicClock)
		{
			this.settings = settings ?? throw new ArgumentNullException("settings");
			this.world = world ?? throw new ArgumentNullException("world");
			clock = monotonicClock ?? throw new ArgumentNullException("monotonicClock");
		}

		public void RegisterItem(string itemId, int charge = 100)
		{
			EnsureNotCommitting();
			ValidateItemId(itemId);
			ValidateCharge(charge);
			if (items.ContainsKey(itemId))
			{
				throw new InvalidOperationException("Item already registered.");
			}
			items.Add(itemId, new ItemState(charge));
		}

		public void RemoveItem(string itemId)
		{
			EnsureNotCommitting();
			items.Remove(itemId);
		}

		public int GetCharge(string itemId)
		{
			if (!items.TryGetValue(itemId, out ItemState value))
			{
				throw new ArgumentException("Unknown item.", "itemId");
			}
			return value.Charge;
		}

		public void UpdateChargeFromCharger(string itemId, int charge)
		{
			EnsureNotCommitting();
			ValidateCharge(charge);
			if (!items.TryGetValue(itemId, out ItemState value))
			{
				throw new ArgumentException("Unknown item.");
			}
			value.Session = null;
			value.Charge = charge;
		}

		public Result Hold(int authenticatedActor, string itemId, int targetActor)
		{
			EnsureNotCommitting();
			double num = ReadTime();
			Expire(num);
			if (authenticatedActor <= 0 || targetActor <= 0 || authenticatedActor == targetActor || string.IsNullOrWhiteSpace(itemId))
			{
				return new Result(Outcome.InvalidRequest, 0.0, 0);
			}
			if (!items.TryGetValue(itemId, out ItemState value))
			{
				return new Result(Outcome.ItemUnavailable, 0.0, 0);
			}
			Session session = value.Session;
			if (session != null && session.Actor != authenticatedActor)
			{
				return Respond(Outcome.Busy, value);
			}
			if (session != null && session.Target != targetActor)
			{
				value.Session = null;
				session = null;
			}
			Observation observation = world.Observe(authenticatedActor, itemId, targetActor);
			if (!Eligible(observation) || completedLives.Contains(LifeKey(targetActor, observation.TargetLifeId)))
			{
				value.Session = null;
				return Respond(Outcome.InvalidTarget, value);
			}
			if (value.Charge < settings.BatteryCost)
			{
				value.Session = null;
				return Respond(Outcome.EmptyBattery, value);
			}
			if (session != null && (session.Damage != observation.DamageRevision || session.Life != observation.TargetLifeId))
			{
				value.Session = null;
				return Respond(Outcome.Interrupted, value);
			}
			if (session == null)
			{
				foreach (ItemState value2 in items.Values)
				{
					if (value2.Session != null && (value2.Session.Target == targetActor || value2.Session.Actor == authenticatedActor))
					{
						return Respond(Outcome.Busy, value);
					}
				}
				value.Session = new Session
				{
					Actor = authenticatedActor,
					Target = targetActor,
					Life = observation.TargetLifeId,
					Damage = observation.DamageRevision,
					Started = num,
					LastHeartbeat = num
				};
				return Respond(Outcome.Charging, value);
			}
			session.LastHeartbeat = num;
			double num2 = Math.Min(1.0, (num - session.Started) / settings.HoldSeconds);
			if (num2 < 1.0)
			{
				return new Result(Outcome.Charging, num2, value.Charge);
			}
			value.Session = null;
			inCommit = true;
			bool flag;
			try
			{
				flag = world.TryRevive(authenticatedActor, targetActor, session.Life, settings.RevivalHealth);
			}
			finally
			{
				inCommit = false;
			}
			if (!flag)
			{
				return Respond(Outcome.RevivalFailed, value);
			}
			completedLives.Add(LifeKey(targetActor, session.Life));
			value.Charge -= settings.BatteryCost;
			return new Result(Outcome.Revived, 1.0, value.Charge);
		}

		public Result Release(int authenticatedActor, string itemId)
		{
			EnsureNotCommitting();
			if (!items.TryGetValue(itemId, out ItemState value))
			{
				return new Result(Outcome.ItemUnavailable, 0.0, 0);
			}
			if (value.Session != null && value.Session.Actor != authenticatedActor)
			{
				return Respond(Outcome.Busy, value);
			}
			value.Session = null;
			return Respond(Outcome.Cancelled, value);
		}

		public void Tick()
		{
			EnsureNotCommitting();
			Expire(ReadTime());
			foreach (KeyValuePair<string, ItemState> item in items)
			{
				Session session = item.Value.Session;
				if (session != null)
				{
					Observation observation = world.Observe(session.Actor, item.Key, session.Target);
					if (!Eligible(observation) || observation.DamageRevision != session.Damage || observation.TargetLifeId != session.Life)
					{
						item.Value.Session = null;
					}
				}
			}
		}

		public void CancelActor(int actorId)
		{
			EnsureNotCommitting();
			foreach (ItemState value in items.Values)
			{
				if (value.Session != null && (value.Session.Actor == actorId || value.Session.Target == actorId))
				{
					value.Session = null;
				}
			}
		}

		public void CancelAll()
		{
			EnsureNotCommitting();
			foreach (ItemState value in items.Values)
			{
				value.Session = null;
			}
		}

		private void Expire(double now)
		{
			foreach (ItemState value in items.Values)
			{
				if (value.Session != null && now - value.Session.LastHeartbeat > settings.HeartbeatTimeoutSeconds)
				{
					value.Session = null;
				}
			}
		}

		private bool Eligible(Observation observation)
		{
			if (observation != null && observation.RoundAllowsRevival && observation.OperatorAlive && observation.OperatorHoldsItem && observation.TargetDead && observation.HasLineOfSight && Settings.Finite(observation.DistanceMeters) && observation.DistanceMeters >= 0.0 && observation.DistanceMeters <= settings.RangeMeters)
			{
				return !string.IsNullOrWhiteSpace(observation.TargetLifeId);
			}
			return false;
		}

		private double ReadTime()
		{
			double num = clock();
			if (!Settings.Finite(num) || num < lastTime)
			{
				throw new InvalidOperationException("Clock must be finite and monotonic.");
			}
			lastTime = num;
			return num;
		}

		private void EnsureNotCommitting()
		{
			if (inCommit)
			{
				throw new InvalidOperationException("Revival callbacks must not reenter the service.");
			}
		}

		private static void ValidateCharge(int charge)
		{
			if (charge < 0 || charge > 100)
			{
				throw new ArgumentOutOfRangeException("charge");
			}
		}

		private static void ValidateItemId(string itemId)
		{
			if (string.IsNullOrWhiteSpace(itemId))
			{
				throw new ArgumentException("An item ID is required.", "itemId");
			}
		}

		private static string LifeKey(int target, string life)
		{
			return target + ":" + life;
		}

		private static Result Respond(Outcome outcome, ItemState item)
		{
			return new Result(outcome, 0.0, item.Charge);
		}
	}
	public sealed class Settings
	{
		public double HoldSeconds { get; }

		public double RangeMeters { get; }

		public int RevivalHealth { get; }

		public int BatteryCost { get; }

		public int Price { get; }

		public double HeartbeatTimeoutSeconds { get; }

		public Settings(double holdSeconds = 3.0, double rangeMeters = 2.0, int revivalHealth = 1, int batteryCost = 50, int price = 2, double heartbeatTimeoutSeconds = 0.75)
		{
			if (!Finite(holdSeconds) || holdSeconds < 0.25 || holdSeconds > 30.0)
			{
				throw new ArgumentOutOfRangeException("holdSeconds");
			}
			if (!Finite(rangeMeters) || rangeMeters <= 0.0 || rangeMeters > 10.0)
			{
				throw new ArgumentOutOfRangeException("rangeMeters");
			}
			if (revivalHealth < 1 || revivalHealth > 100)
			{
				throw new ArgumentOutOfRangeException("revivalHealth");
			}
			if (batteryCost < 1 || batteryCost > 100)
			{
				throw new ArgumentOutOfRangeException("batteryCost");
			}
			if (price < 0)
			{
				throw new ArgumentOutOfRangeException("price");
			}
			if (!Finite(heartbeatTimeoutSeconds) || heartbeatTimeoutSeconds <= 0.0 || heartbeatTimeoutSeconds > 2.0)
			{
				throw new ArgumentOutOfRangeException("heartbeatTimeoutSeconds");
			}
			HoldSeconds = holdSeconds;
			RangeMeters = rangeMeters;
			RevivalHealth = revivalHealth;
			BatteryCost = batteryCost;
			Price = price;
			HeartbeatTimeoutSeconds = heartbeatTimeoutSeconds;
		}

		internal static bool Finite(double value)
		{
			if (!double.IsNaN(value))
			{
				return !double.IsInfinity(value);
			}
			return false;
		}
	}
	public sealed class VoiceEffect
	{
		public float Pitch { get; }

		public double VoiceExpiresAt { get; }

		public double NextShockAt { get; private set; }

		public double ShockInterval { get; }

		public int Sequence { get; private set; }

		public double NextAnimalAt { get; private set; }

		public double AnimalInterval { get; }

		public int AnimalSequence { get; private set; }

		public string Round { get; }

		public string Token { get; }

		public VoiceEffect(float pitch, double voiceExpiresAt, double nextShockAt, double shockInterval, string round, string token, int sequence = 0, double? nextAnimalAt = null, double animalInterval = 30.0, int animalSequence = 0)
		{
			if (!Settings.Finite(pitch) || pitch < 0.5f || pitch > 2f)
			{
				throw new ArgumentOutOfRangeException("pitch");
			}
			if (!Settings.Finite(voiceExpiresAt) || voiceExpiresAt < 0.0)
			{
				throw new ArgumentOutOfRangeException("voiceExpiresAt");
			}
			if (!Settings.Finite(nextShockAt) || nextShockAt < 0.0)
			{
				throw new ArgumentOutOfRangeException("nextShockAt");
			}
			if (!Settings.Finite(shockInterval) || shockInterval < 5.0 || shockInterval > 300.0)
			{
				throw new ArgumentOutOfRangeException("shockInterval");
			}
			if (string.IsNullOrWhiteSpace(round))
			{
				throw new ArgumentException("A round identity is required.", "round");
			}
			if (string.IsNullOrWhiteSpace(token))
			{
				throw new ArgumentException("An effect identity is required.", "token");
			}
			if (sequence < 0)
			{
				throw new ArgumentOutOfRangeException("sequence");
			}
			if (!Settings.Finite(animalInterval) || animalInterval < 5.0 || animalInterval > 300.0 || !Settings.Finite(nextAnimalAt ?? nextShockAt) || (nextAnimalAt ?? nextShockAt) < 0.0 || animalSequence < 0)
			{
				throw new ArgumentOutOfRangeException("animalInterval");
			}
			Pitch = pitch;
			VoiceExpiresAt = voiceExpiresAt;
			NextShockAt = nextShockAt;
			ShockInterval = shockInterval;
			Round = round;
			Token = token;
			Sequence = sequence;
			NextAnimalAt = nextAnimalAt ?? nextShockAt;
			AnimalInterval = animalInterval;
			AnimalSequence = animalSequence;
		}

		public bool IsActive(double now, string round, bool playerAlive)
		{
			return Settings.Finite(now) && Round == round && playerAlive;
		}

		public bool HasVoice(double now, string round, bool playerAlive)
		{
			if (IsActive(now, round, playerAlive))
			{
				return now < VoiceExpiresAt;
			}
			return false;
		}

		public bool TryShock(double now, string round, bool playerAlive)
		{
			if (!IsActive(now, round, playerAlive) || now < NextShockAt)
			{
				return false;
			}
			NextShockAt = now + ShockInterval;
			checked
			{
				Sequence++;
				return true;
			}
		}

		public bool TryAnimal(double now, string round, bool playerAlive)
		{
			if (!IsActive(now, round, playerAlive) || now < NextAnimalAt)
			{
				return false;
			}
			NextAnimalAt = now + AnimalInterval;
			checked
			{
				AnimalSequence++;
				return true;
			}
		}

		public static float ChoosePitch(int coin, float high = 1.8f, float low = 0.55f)
		{
			if (coin != 0 && coin != 1)
			{
				throw new ArgumentOutOfRangeException("coin");
			}
			if (!Settings.Finite(high) || high <= 1f || high > 2f || !Settings.Finite(low) || low < 0.5f || low >= 1f)
			{
				throw new ArgumentOutOfRangeException("high", "High must be in (1,2]; low must be in [0.5,1).");
			}
			if (coin != 0)
			{
				return low;
			}
			return high;
		}
	}
	public sealed class Observation
	{
		public bool RoundAllowsRevival { get; }

		public bool OperatorAlive { get; }

		public bool OperatorHoldsItem { get; }

		public bool TargetDead { get; }

		public bool HasLineOfSight { get; }

		public double DistanceMeters { get; }

		public long DamageRevision { get; }

		public string TargetLifeId { get; }

		public Observation(bool roundAllowsRevival, bool operatorAlive, bool operatorHoldsItem, bool targetDead, bool hasLineOfSight, double distanceMeters, long damageRevision, string targetLifeId)
		{
			RoundAllowsRevival = roundAllowsRevival;
			OperatorAlive = operatorAlive;
			OperatorHoldsItem = operatorHoldsItem;
			TargetDead = targetDead;
			HasLineOfSight = hasLineOfSight;
			DistanceMeters = distanceMeters;
			DamageRevision = damageRevision;
			TargetLifeId = targetLifeId;
		}
	}
	public interface IRevivalWorld
	{
		Observation Observe(int actorId, string itemId, int targetActorId);

		bool TryRevive(int actorId, int targetActorId, string targetLifeId, int health);
	}
}

BepInEx/plugins/IndustrialDefibrillator/Defibrillator.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using Defibrillator.Core;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using REPOLib.Modules;
using TMPro;
using UnityEngine;
using UnityEngine.Events;

[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("0.1.5.0")]
[assembly: AssemblyInformationalVersion("0.1.5+9d197fcbfb4d444b476161ad58b79e319e14f80f")]
[assembly: AssemblyProduct("Defibrillator")]
[assembly: AssemblyTitle("Defibrillator")]
[assembly: AssemblyVersion("0.1.5.0")]
[module: RefSafetyRules(11)]
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 Defibrillator.Mod
{
	public sealed class AftershockCamera : MonoBehaviour
	{
		private PlayerAvatar target;

		private float started;

		private float duration;

		private float yaw;

		private float delivered;

		internal static void Spawn(PlayerAvatar player, float degrees, float seconds)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (GameAccess.IsLocal(player) && degrees != 0f)
			{
				AftershockCamera aftershockCamera = new GameObject("Defibrillator camera jolt").AddComponent<AftershockCamera>();
				aftershockCamera.target = player;
				aftershockCamera.started = Time.unscaledTime;
				aftershockCamera.duration = Mathf.Min(0.65f, seconds);
				aftershockCamera.yaw = degrees;
			}
		}

		private void Update()
		{
			if (!Object.op_Implicit((Object)(object)target) || !GameAccess.IsLocal(target) || !GameAccess.IsAlive(target) || !Object.op_Implicit((Object)(object)RunManager.instance) || !SemiFunc.RunIsLevel() || !Object.op_Implicit((Object)(object)CameraAim.Instance) || !Object.op_Implicit((Object)(object)GameDirector.instance) || GameDirector.instance.DisableInput || !GameAccess.InputAllowed())
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			float num = (Time.unscaledTime - started) / duration;
			float num2 = AftershockImpact.YawAt(yaw, (double)num);
			CameraAim.Instance.AdditiveAimX(num2 - delivered);
			delivered = num2;
			if (num >= 1f)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}
	public sealed class AftershockVisual : MonoBehaviour
	{
		private PlayerAvatar target;

		private readonly LineRenderer[] arcs = (LineRenderer[])(object)new LineRenderer[7];

		private float ends;

		private int seed;

		private Material material;

		internal static void Spawn(PlayerAvatar player, int sequence, float strength, float seconds)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			if (GameAccess.IsLocal(player) && Object.op_Implicit((Object)(object)GameDirector.instance) && Object.op_Implicit((Object)(object)GameDirector.instance.CameraShake))
			{
				GameDirector.instance.CameraShake.Shake(strength, seconds, 0f);
			}
			GameObject val = new GameObject("Defibrillator harmless aftershock");
			AftershockVisual aftershockVisual = val.AddComponent<AftershockVisual>();
			aftershockVisual.target = player;
			aftershockVisual.ends = Time.unscaledTime + seconds;
			aftershockVisual.seed = sequence;
			Shader val2 = Shader.Find("Sprites/Default") ?? Shader.Find("Standard");
			if (!Object.op_Implicit((Object)(object)val2))
			{
				Plugin.Error("No aftershock shader found; camera shake applied but visible arcs unavailable.");
				Object.Destroy((Object)(object)val);
				return;
			}
			aftershockVisual.material = new Material(val2);
			aftershockVisual.material.color = new Color(0.3f, 0.8f, 1f, 1f);
			for (int i = 0; i < aftershockVisual.arcs.Length; i++)
			{
				GameObject val3 = new GameObject("Electrical arc");
				val3.transform.SetParent(val.transform, false);
				LineRenderer val4 = val3.AddComponent<LineRenderer>();
				val4.useWorldSpace = false;
				((Renderer)val4).sharedMaterial = aftershockVisual.material;
				val4.positionCount = 9;
				val4.startWidth = 0.035f;
				val4.endWidth = 0.018f;
				aftershockVisual.arcs[i] = val4;
			}
			AudioSource obj = val.AddComponent<AudioSource>();
			obj.spatialBlend = 1f;
			obj.rolloffMode = (AudioRolloffMode)1;
			obj.minDistance = 1f;
			obj.maxDistance = 14f;
			obj.volume = 0.45f;
			obj.PlayOneShot(OriginalAssets.Shock);
		}

		private void Update()
		{
			//IL_0057: 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_0066: 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_0121: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)target) || !GameAccess.IsAlive(target) || !Object.op_Implicit((Object)(object)RunManager.instance) || !SemiFunc.RunIsLevel() || Time.unscaledTime >= ends)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			((Component)this).transform.position = ((Component)target).transform.position + Vector3.up * 0.3f;
			for (int i = 0; i < arcs.Length; i++)
			{
				if (Object.op_Implicit((Object)(object)arcs[i]))
				{
					for (int j = 0; j < 9; j++)
					{
						float num = (float)j / 8f;
						float num2 = (float)i * MathF.PI * 2f / (float)arcs.Length + num * 2f + (float)seed;
						float num3 = Mathf.Sin(Time.unscaledTime * 83f + (float)(j * 5) + (float)(i * 11)) * 0.12f;
						arcs[i].SetPosition(j, new Vector3(Mathf.Cos(num2) * (0.4f + num3), Mathf.Lerp(-0.35f, 0.65f, num), Mathf.Sin(num2) * (0.4f + num3)));
					}
				}
			}
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)material))
			{
				Object.Destroy((Object)(object)material);
			}
		}
	}
	internal static class AnimalClips
	{
		internal static readonly string[] Names = new string[4] { "sheep", "cat", "dog", "horse" };

		private static readonly AudioClip[] clips = (AudioClip[])(object)new AudioClip[4];

		private static readonly PcmWave[] data = (PcmWave[])(object)new PcmWave[4];

		internal static bool Ready { get; private set; }

		internal static void Load()
		{
			try
			{
				for (int i = 0; i < Names.Length; i++)
				{
					using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Defibrillator.Animals." + Names[i] + ".wav") ?? throw new InvalidDataException("Missing embedded animal clip: " + Names[i]);
					data[i] = PcmWave.Read(stream);
					clips[i] = AudioClip.Create("Defibrillator " + Names[i], data[i].Samples.Length, 1, data[i].SampleRate, false);
					if (!clips[i].SetData(data[i].Samples, 0))
					{
						throw new InvalidDataException("Could not load animal PCM data.");
					}
				}
				Ready = true;
				Plugin.LogInfo("Loaded four embedded animal recordings, each at most three seconds.");
			}
			catch (Exception ex)
			{
				Ready = false;
				AudioClip[] array = clips;
				foreach (AudioClip val in array)
				{
					if (Object.op_Implicit((Object)(object)val))
					{
						Object.Destroy((Object)(object)val);
					}
				}
				Plugin.Error("Animal audio disabled; normal voice is preserved. " + ex);
			}
		}

		internal static AudioClip Get(int index)
		{
			return clips[index];
		}

		internal static float Level(int index, int sample)
		{
			float[] samples = data[index].Samples;
			double num = 0.0;
			int num2 = Math.Max(0, Math.Min(sample, samples.Length - 1));
			int num3 = Math.Min(512, samples.Length - num2);
			for (int i = num2; i < num2 + num3; i++)
			{
				num += (double)(samples[i] * samples[i]);
			}
			return Mathf.Clamp((float)Math.Sqrt(num / (double)num3) * 2f, 0f, 0.25f);
		}
	}
	public sealed class AnimalVoicePlayback : MonoBehaviour
	{
		private static readonly Dictionary<int, AnimalVoicePlayback> active = new Dictionary<int, AnimalVoicePlayback>();

		private static readonly FieldInfo talking = AccessTools.Field(typeof(PlayerVoiceChat), "isTalking");

		private static readonly FieldInfo loudness = AccessTools.Field(typeof(PlayerVoiceChat), "clipLoudness");

		private static readonly FieldInfo talkStart = AccessTools.Field(typeof(PlayerVoiceChat), "isTalkingStartTime");

		private static readonly FieldInfo voiceGain = AccessTools.Field(typeof(PlayerVoiceChat), "voiceGain");

		private PlayerAvatar target;

		private PlayerVoiceChat voice;

		private AudioSource source;

		private string token = "";

		private int id;

		private int animal;

		private double ends;

		private float started;

		private bool overridden;

		private bool nativeTalking;

		private float nativeLoudness;

		private float nativeStart;

		private bool Playing
		{
			get
			{
				if (Object.op_Implicit((Object)(object)target) && Object.op_Implicit((Object)(object)voice) && Object.op_Implicit((Object)(object)source) && source.isPlaying && VoiceDebuffs.Now < ends && GameAccess.IsAlive(target) && Object.op_Implicit((Object)(object)RunManager.instance) && SemiFunc.RunIsLevel() && VoiceDebuffs.Effects.TryGetValue(id, out VoiceEffect value))
				{
					return value.Token == token;
				}
				return false;
			}
		}

		internal static void Play(int targetId, string effectToken, int index, double at)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			//IL_00d8: 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_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Invalid comparison between Unknown and I4
			if (!AnimalClips.Ready || index < 0 || index >= 4)
			{
				return;
			}
			PlayerAvatar val = GameAccess.FindPlayer(targetId);
			PlayerVoiceChat val2 = (Object.op_Implicit((Object)(object)val) ? GameAccess.Voice(val) : null);
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val2))
			{
				return;
			}
			AudioClip val3 = AnimalClips.Get(index);
			double num = VoiceDebuffs.Now - at;
			if (!(num < -1.0) && !(num >= (double)val3.length))
			{
				Stop(targetId);
				GameObject val4 = new GameObject("Defibrillator animal voice - " + AnimalClips.Names[index]);
				AnimalVoicePlayback animalVoicePlayback = val4.AddComponent<AnimalVoicePlayback>();
				animalVoicePlayback.id = targetId;
				animalVoicePlayback.target = val;
				animalVoicePlayback.voice = val2;
				animalVoicePlayback.token = effectToken;
				animalVoicePlayback.animal = index;
				animalVoicePlayback.ends = at + (double)val3.length;
				animalVoicePlayback.started = Time.time;
				val4.transform.position = ((Component)val2).transform.position;
				animalVoicePlayback.source = val4.AddComponent<AudioSource>();
				AudioSource component = ((Component)val2).GetComponent<AudioSource>();
				animalVoicePlayback.source.clip = val3;
				animalVoicePlayback.source.pitch = 1f;
				animalVoicePlayback.source.dopplerLevel = 0f;
				animalVoicePlayback.source.playOnAwake = false;
				animalVoicePlayback.source.loop = false;
				animalVoicePlayback.source.spatialBlend = (GameAccess.IsLocal(val) ? 0f : component.spatialBlend);
				animalVoicePlayback.source.rolloffMode = component.rolloffMode;
				animalVoicePlayback.source.minDistance = component.minDistance;
				animalVoicePlayback.source.maxDistance = component.maxDistance;
				if ((int)component.rolloffMode == 2)
				{
					animalVoicePlayback.source.SetCustomCurve((AudioSourceCurveType)0, component.GetCustomCurve((AudioSourceCurveType)0));
				}
				animalVoicePlayback.source.outputAudioMixerGroup = val2.mixerMicrophoneSound;
				animalVoicePlayback.source.volume = VoiceDebuffs.AnimalVolume * (GameAccess.IsLocal(val) ? 1f : Mathf.Clamp01((float)voiceGain.GetValue(val2) * 2f));
				active[targetId] = animalVoicePlayback;
				animalVoicePlayback.source.Play();
				animalVoicePlayback.source.time = Mathf.Max(0f, (float)num);
			}
		}

		private void Update()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (!Playing)
			{
				Stop(id);
				return;
			}
			((Component)this).transform.position = ((Component)voice).transform.position;
			source.outputAudioMixerGroup = voice.mixerMicrophoneSound;
			source.volume = VoiceDebuffs.AnimalVolume * (GameAccess.IsLocal(target) ? 1f : Mathf.Clamp01((float)voiceGain.GetValue(voice) * 2f));
		}

		internal static void BeforeVoice(PlayerVoiceChat instance)
		{
			foreach (AnimalVoicePlayback value in active.Values)
			{
				if ((Object)(object)value.voice == (Object)(object)instance)
				{
					value.Restore();
					if (value.Playing)
					{
						instance.OverrideVolumeMute(0.05f);
					}
				}
			}
		}

		internal static void AfterVoice(PlayerVoiceChat instance)
		{
			foreach (AnimalVoicePlayback value in active.Values)
			{
				if ((Object)(object)value.voice == (Object)(object)instance && value.Playing)
				{
					value.nativeTalking = (bool)talking.GetValue(instance);
					value.nativeLoudness = (float)loudness.GetValue(instance);
					value.nativeStart = (float)talkStart.GetValue(instance);
					float num = AnimalClips.Level(value.animal, value.source.timeSamples);
					talking.SetValue(instance, num > 0.005f);
					loudness.SetValue(instance, num);
					talkStart.SetValue(instance, value.started);
					value.overridden = true;
				}
			}
		}

		private void Restore()
		{
			if (overridden && Object.op_Implicit((Object)(object)voice))
			{
				talking.SetValue(voice, nativeTalking);
				loudness.SetValue(voice, nativeLoudness);
				talkStart.SetValue(voice, nativeStart);
				overridden = false;
			}
		}

		internal static void Stop(int targetId)
		{
			if (active.TryGetValue(targetId, out AnimalVoicePlayback value))
			{
				active.Remove(targetId);
				value.Restore();
				if (Object.op_Implicit((Object)(object)value.source))
				{
					value.source.Stop();
				}
				Object.Destroy((Object)(object)((Component)value).gameObject);
			}
		}

		internal static void StopAll()
		{
			foreach (int item in new List<int>(active.Keys))
			{
				Stop(item);
			}
		}

		private void OnDestroy()
		{
			Restore();
			if (active.TryGetValue(id, out AnimalVoicePlayback value) && (Object)(object)value == (Object)(object)this)
			{
				active.Remove(id);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerVoiceChat), "IsTalkingRPC")]
	internal static class AnimalTalkingRpcPatch
	{
		[HarmonyPrefix]
		private static void Prefix(PlayerVoiceChat __instance)
		{
			AnimalVoicePlayback.BeforeVoice(__instance);
		}

		[HarmonyPostfix]
		private static void Postfix(PlayerVoiceChat __instance)
		{
			AnimalVoicePlayback.AfterVoice(__instance);
		}
	}
	internal static class BatteryDisplayFallback
	{
		internal static BatteryVisualLogic? FindTemplate()
		{
			if (Object.op_Implicit((Object)(object)BatteryUI.instance) && SelfContained(BatteryUI.instance.batteryVisualLogic))
			{
				return BatteryUI.instance.batteryVisualLogic;
			}
			BatteryVisualLogic[] array = Resources.FindObjectsOfTypeAll<BatteryVisualLogic>();
			foreach (BatteryVisualLogic val in array)
			{
				if (SelfContained(val))
				{
					return val;
				}
			}
			return null;
		}

		private static bool SelfContained(BatteryVisualLogic visual)
		{
			if (!Object.op_Implicit((Object)(object)visual) || !Object.op_Implicit((Object)(object)visual.batteryBarPrefab) || !Object.op_Implicit((Object)(object)visual.barLossEffectPrefab))
			{
				return false;
			}
			if (Owns(visual, (Component)(object)visual.batteryBarContainerGroup) && Owns(visual, (Component)(object)visual.batteryBarContainer) && Owns(visual, (Component)(object)visual.batteryBarCharge) && Owns(visual, (Component)(object)visual.batteryBarDrain) && Owns(visual, (Component)(object)visual.batteryBorderShadow) && Owns(visual, (Component)(object)visual.batteryBorderMain) && Owns(visual, (Component)(object)visual.batteryBackground) && Owns(visual, (Component)(object)visual.batteryCharge) && Owns(visual, (Component)(object)visual.batteryDrain) && Object.op_Implicit((Object)(object)visual.batteryOutVisual) && Object.op_Implicit((Object)(object)visual.batteryChargeNeededVisual) && visual.batteryOutVisual.transform.IsChildOf(((Component)visual).transform))
			{
				return visual.batteryChargeNeededVisual.transform.IsChildOf(((Component)visual).transform);
			}
			return false;
		}

		private static bool Owns(BatteryVisualLogic root, Component component)
		{
			if (Object.op_Implicit((Object)(object)component))
			{
				if (!((Object)(object)component.transform == (Object)(object)((Component)root).transform))
				{
					return component.transform.IsChildOf(((Component)root).transform);
				}
				return true;
			}
			return false;
		}

		internal static void Attach(GameObject prefab, BatteryVisualLogic template)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			GameObject val = new GameObject("Defibrillator native battery bookkeeping", new Type[2]
			{
				typeof(RectTransform),
				typeof(Canvas)
			});
			val.transform.SetParent(prefab.transform, false);
			((Behaviour)val.GetComponent<Canvas>()).enabled = false;
			GameObject val2 = Object.Instantiate<GameObject>(((Component)template).gameObject, val.transform);
			((Object)val2).name = "Private battery display";
			BatteryVisualLogic component = val2.GetComponent<BatteryVisualLogic>();
			component.inUI = true;
			component.cameraTurn = false;
			component.itemBattery = prefab.GetComponent<ItemBattery>();
			Canvas[] componentsInChildren = val2.GetComponentsInChildren<Canvas>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				((Behaviour)componentsInChildren[i]).enabled = false;
			}
			val2.SetActive(true);
			prefab.GetComponent<ItemBattery>().hasBatteryVisuals = false;
			Plugin.LogInfo("Attached a private native battery-display fallback; the shared HUD is unchanged.");
		}
	}
	public sealed class Device : MonoBehaviour
	{
		internal static readonly HashSet<Device> Active = new HashSet<Device>();

		internal ItemAttributes Attributes;

		internal ItemBattery Battery;

		internal PhotonView View;

		private PhysGrabObject physical;

		private RevivalService? registeredWith;

		private string registeredId = "";

		private bool started;

		private float nextInput;

		private bool holding;

		private int lastOperator;

		private float progress;

		private string message = "Aim at a dead player's head and hold Interact";

		private float lastFeedback;

		private AudioSource audioSource;

		private Renderer[] indicators = Array.Empty<Renderer>();

		private readonly MaterialPropertyBlock indicatorColor = new MaterialPropertyBlock();

		internal string Id
		{
			get
			{
				if (!SemiFunc.IsMultiplayer())
				{
					return "local:" + ((Object)this).GetInstanceID();
				}
				return "net:" + View.ViewID;
			}
		}

		internal bool Ready
		{
			get
			{
				if (started)
				{
					if (SemiFunc.IsMultiplayer())
					{
						return View.ViewID > 0;
					}
					return true;
				}
				return false;
			}
		}

		internal int NetworkId => View.ViewID;

		private void OnEnable()
		{
			Active.Add(this);
		}

		private IEnumerator Start()
		{
			Attributes = ((Component)this).GetComponent<ItemAttributes>();
			Battery = ((Component)this).GetComponent<ItemBattery>();
			physical = ((Component)this).GetComponent<PhysGrabObject>();
			View = ((Component)this).GetComponent<PhotonView>();
			audioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
			audioSource.spatialBlend = 1f;
			audioSource.rolloffMode = (AudioRolloffMode)1;
			audioSource.minDistance = 1f;
			audioSource.maxDistance = 12f;
			audioSource.volume = 0.45f;
			audioSource.playOnAwake = false;
			indicators = (from renderer in ((Component)this).GetComponentsInChildren<Renderer>(true)
				where ((Object)renderer).name.StartsWith("Cell ")
				select renderer).ToArray();
			yield return null;
			((Component)this).GetComponent<Rigidbody>().ResetInertiaTensor();
			started = true;
		}

		internal bool IsHeldBy(PlayerAvatar player)
		{
			if (Object.op_Implicit((Object)(object)physical))
			{
				return physical.playerGrabbing.Any((PhysGrabber grabber) => Object.op_Implicit((Object)(object)grabber) && (Object)(object)grabber.playerAvatar == (Object)(object)player);
			}
			return false;
		}

		internal void SyncHostBattery()
		{
			RevivalService service = Plugin.Service;
			if (!Ready || service == null)
			{
				return;
			}
			int num = Mathf.FloorToInt(Mathf.Clamp(Battery.batteryLife, 0f, 100f));
			if (registeredWith != service || registeredId != Id)
			{
				RevivalService? obj = registeredWith;
				if (obj != null)
				{
					obj.RemoveItem(registeredId);
				}
				service.RegisterItem(Id, num);
				registeredWith = service;
				registeredId = Id;
			}
			else if (service.GetCharge(Id) != num)
			{
				service.UpdateChargeFromCharger(Id, num);
			}
		}

		private void Update()
		{
			//IL_0076: 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_007b: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)Plugin.Instance) || !Plugin.Instance.Operational || !Ready || !Object.op_Implicit((Object)(object)PlayerAvatar.instance) || !Object.op_Implicit((Object)(object)RunManager.instance))
			{
				return;
			}
			for (int i = 0; i < indicators.Length; i++)
			{
				Color val = ((Battery.batteryLife >= (float)((i + 1) * 25)) ? new Color(0.15f, 0.95f, 0.3f) : new Color(0.04f, 0.06f, 0.04f));
				indicatorColor.SetColor("_Color", val);
				indicatorColor.SetColor("_BaseColor", val);
				indicators[i].SetPropertyBlock(indicatorColor);
			}
			PlayerAvatar instance = PlayerAvatar.instance;
			if (!IsHeldBy(instance) || !GameAccess.IsLocal(instance) || !SemiFunc.RunIsLevel() || !GameAccess.InputAllowed() || !GameAccess.IsAlive(instance) || !SemiFunc.InputHold((InputKey)2))
			{
				if (holding)
				{
					Plugin.Instance.Network.Send(this, lastOperator, 0, release: true);
				}
				holding = false;
				progress = 0f;
				return;
			}
			int actor = GameAccess.PlayerId(instance);
			int num = FindAimedTarget(instance);
			if (num == 0)
			{
				if (holding)
				{
					Plugin.Instance.Network.Send(this, actor, 0, release: true);
				}
				holding = false;
				progress = 0f;
				message = "Aim at a dead player's head within range";
			}
			else if (!(Time.unscaledTime < nextInput))
			{
				nextInput = Time.unscaledTime + 0.15f;
				holding = true;
				lastOperator = actor;
				Plugin.Instance.Network.Send(this, actor, num, release: false);
			}
		}

		private int FindAimedTarget(PlayerAvatar player)
		{
			if (!Object.op_Implicit((Object)(object)GameDirector.instance))
			{
				return 0;
			}
			int result = 0;
			double num = double.PositiveInfinity;
			foreach (PlayerAvatar player2 in GameDirector.instance.PlayerList)
			{
				if (Object.op_Implicit((Object)(object)player2) && !((Object)(object)player2 == (Object)(object)player))
				{
					Observation val = Plugin.World.Observe(GameAccess.PlayerId(player), Id, GameAccess.PlayerId(player2));
					if (val.TargetDead && val.HasLineOfSight && val.DistanceMeters < num)
					{
						num = val.DistanceMeters;
						result = GameAccess.PlayerId(player2);
					}
				}
			}
			return result;
		}

		internal void Feedback(int operatorId, Outcome outcome, float value, int charge)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected I4, but got Unknown
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			if ((int)outcome == 1)
			{
				audioSource.PlayOneShot(OriginalAssets.Shock);
			}
			if (Object.op_Implicit((Object)(object)PlayerAvatar.instance) && GameAccess.PlayerId(PlayerAvatar.instance) == operatorId)
			{
				progress = Mathf.Clamp01(value);
				lastFeedback = Time.unscaledTime;
				message = (int)outcome switch
				{
					0 => "Charging — keep holding Interact", 
					1 => "Revived • battery " + charge + "%", 
					7 => "Recharge the defibrillator", 
					6 => "Another revival is in progress", 
					8 => "Revival interrupted", 
					4 => "Target unavailable or out of range", 
					10 => "Revival failed — no battery consumed", 
					_ => "Aim at a dead player's head and hold Interact", 
				};
				if ((int)outcome == 0 && value == 0f)
				{
					audioSource.PlayOneShot(OriginalAssets.StartCharge);
				}
			}
		}

		private void OnGUI()
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			if (Ready && Object.op_Implicit((Object)(object)PlayerAvatar.instance) && IsHeldBy(PlayerAvatar.instance) && SemiFunc.RunIsLevel())
			{
				if (holding && Time.unscaledTime - lastFeedback > 1.5f)
				{
					progress = 0f;
					message = "Waiting for host";
				}
				Rect val = default(Rect);
				((Rect)(ref val))..ctor((float)Screen.width / 2f - 190f, (float)Screen.height / 2f + 70f, 380f, 65f);
				GUI.Box(val, "DEFIBRILLATOR • " + Mathf.FloorToInt(Battery.batteryLife) + "%\n" + message);
				GUI.Box(new Rect(((Rect)(ref val)).x + 10f, ((Rect)(ref val)).y + 48f, 360f * progress, 8f), "");
			}
		}

		private void OnDisable()
		{
			Active.Remove(this);
			if (holding && Object.op_Implicit((Object)(object)Plugin.Instance) && Plugin.Instance.Network != null && Object.op_Implicit((Object)(object)GameManager.instance) && Ready)
			{
				Plugin.Instance.Network.Send(this, lastOperator, 0, release: true);
			}
			RevivalService? obj = registeredWith;
			if (obj != null)
			{
				obj.RemoveItem(registeredId);
			}
			registeredWith = null;
			holding = false;
		}

		internal void ResetInput()
		{
			holding = false;
			progress = 0f;
			nextInput = 0f;
			message = "Aim at a dead player's head and hold Interact";
		}
	}
	internal static class DevicePhysics
	{
		internal static void ConfigurePrefab(GameObject prefab)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: 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_00e4: 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_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: 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_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_0329: Unknown result type (might be due to invalid IL or missing references)
			prefab.transform.localScale = Vector3.one;
			prefab.transform.localPosition = Vector3.zero;
			prefab.transform.localRotation = Quaternion.identity;
			PhysGrabObject component = prefab.GetComponent<PhysGrabObject>();
			PhysGrabObjectCollider[] componentsInChildren = prefab.GetComponentsInChildren<PhysGrabObjectCollider>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			PhysGrabObjectBoxCollider[] componentsInChildren2 = prefab.GetComponentsInChildren<PhysGrabObjectBoxCollider>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren2[i]);
			}
			Collider[] componentsInChildren3 = prefab.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren3[i]);
			}
			component.colliders.Clear();
			foreach (CollisionBox collisionBox in DeviceGeometry.CollisionBoxes)
			{
				CollisionBox current = collisionBox;
				GameObject val = new GameObject("Defibrillator collision - " + ((CollisionBox)(ref current)).Name)
				{
					layer = prefab.layer
				};
				val.transform.SetParent(prefab.transform, false);
				val.transform.localPosition = new Vector3(((CollisionBox)(ref current)).X, ((CollisionBox)(ref current)).Y, ((CollisionBox)(ref current)).Z) * 0.5f;
				val.AddComponent<BoxCollider>().size = new Vector3(((CollisionBox)(ref current)).Width, ((CollisionBox)(ref current)).Height, ((CollisionBox)(ref current)).Depth) * 0.5f;
				val.AddComponent<PhysGrabObjectCollider>();
				val.AddComponent<PhysGrabObjectBoxCollider>().drawGizmos = false;
			}
			Rigidbody component2 = prefab.GetComponent<Rigidbody>();
			component2.mass = 3f;
			component2.useGravity = true;
			component2.linearDamping = 0.35f;
			component2.angularDamping = 1f;
			component2.centerOfMass = new Vector3(0f, -0.015f, 0f);
			component.massOriginal = 3f;
			NotValuableObject component3 = prefab.GetComponent<NotValuableObject>();
			if (Object.op_Implicit((Object)(object)component3))
			{
				PhysAttribute val2 = (Object.op_Implicit((Object)(object)component3.physAttributePreset) ? Object.Instantiate<PhysAttribute>(component3.physAttributePreset) : ScriptableObject.CreateInstance<PhysAttribute>());
				((Object)val2).name = "Industrial Defibrillator physics";
				val2.mass = 3f;
				component3.physAttributePreset = val2;
			}
			Transform val3 = prefab.transform.Find("Center of Mass");
			if (Object.op_Implicit((Object)(object)val3))
			{
				val3.position = prefab.transform.TransformPoint(component2.centerOfMass);
			}
			Transform val4 = prefab.transform.Find("Force Grab Point");
			if (Object.op_Implicit((Object)(object)val4))
			{
				val4.position = prefab.transform.position;
			}
			RoomVolumeCheck component4 = prefab.GetComponent<RoomVolumeCheck>();
			if (Object.op_Implicit((Object)(object)component4))
			{
				component4.CheckPosition = Vector3.zero;
				component4.currentSize = new Vector3(0.35f, 0.24f, 0.13f);
			}
			ItemVolume[] componentsInChildren4 = prefab.GetComponentsInChildren<ItemVolume>(true);
			for (int i = 0; i < componentsInChildren4.Length; i++)
			{
				((Component)componentsInChildren4[i]).transform.position = prefab.transform.TransformPoint(new Vector3(0f, -0.07875f, 0f));
			}
			prefab.GetComponent<ItemAttributes>().costOffset = new Vector3(0f, 0.2f, 0f);
		}
	}
	[HarmonyPatch(typeof(PhysGrabObject), "Awake")]
	internal static class CompactScalePatch
	{
		[HarmonyPrefix]
		private static void Prefix(PhysGrabObject __instance)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<Device>()))
			{
				PhotonView component = ((Component)__instance).GetComponent<PhotonView>();
				object[] array = (Object.op_Implicit((Object)(object)component) ? component.InstantiationData : null);
				if (array != null && array.Length >= 3)
				{
					object[] array2 = (object[])array.Clone();
					array2[0] = (array2[1] = (array2[2] = 1f));
					(AccessTools.PropertySetter(typeof(PhotonView), "InstantiationData") ?? throw new MissingMethodException("PhotonView.InstantiationData setter")).Invoke(component, new object[1] { array2 });
				}
				((Component)__instance).transform.localScale = Vector3.one;
			}
		}
	}
	internal static class GameAccess
	{
		private static readonly FieldInfo Disabled = Require(typeof(PlayerAvatar), "isDisabled");

		private static readonly FieldInfo DeadSet = Require(typeof(PlayerAvatar), "deadSet");

		private static readonly FieldInfo TumbleField = Require(typeof(PlayerAvatar), "tumble");

		private static readonly FieldInfo Tumbling = Require(typeof(PlayerAvatar), "isTumbling");

		private static readonly FieldInfo VoiceField = Require(typeof(PlayerAvatar), "voiceChat");

		private static readonly FieldInfo DeathHead = Require(typeof(PlayerAvatar), "playerDeathHead");

		private static readonly FieldInfo Health = Require(typeof(PlayerHealth), "health");

		private static readonly FieldInfo ShopItem = Require(typeof(ItemAttributes), "shopItem");

		private static readonly FieldInfo ItemValue = Require(typeof(ItemAttributes), "value");

		private static readonly FieldInfo CameraPosition = Require(typeof(PlayerAvatar), "clientCameraPosition");

		private static readonly FieldInfo CameraRotation = Require(typeof(PlayerAvatar), "clientCameraRotation");

		private static readonly FieldInfo InputDisabled = Require(typeof(PlayerController), "InputDisableTimer");

		private static FieldInfo Require(Type type, string field)
		{
			return AccessTools.Field(type, field) ?? throw new MissingFieldException(type.FullName, field);
		}

		internal static void Validate()
		{
			_ = Disabled;
			_ = DeathHead;
			_ = Health;
			_ = ShopItem;
			_ = ItemValue;
			if (AccessTools.Method(typeof(PunManager), "SpawnShopItem", (Type[])null, (Type[])null) == null)
			{
				throw new MissingMethodException("PunManager.SpawnShopItem");
			}
		}

		internal static bool IsDead(PlayerAvatar avatar)
		{
			return (bool)Disabled.GetValue(avatar);
		}

		internal static PlayerTumble? Tumble(PlayerAvatar avatar)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			return (PlayerTumble)TumbleField.GetValue(avatar);
		}

		internal static PlayerVoiceChat? Voice(PlayerAvatar avatar)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			return (PlayerVoiceChat)VoiceField.GetValue(avatar);
		}

		internal static bool IsTumbling(PlayerAvatar avatar)
		{
			return (bool)Tumbling.GetValue(avatar);
		}

		internal static bool IsAlive(PlayerAvatar avatar)
		{
			if (!IsDead(avatar))
			{
				return !(bool)DeadSet.GetValue(avatar);
			}
			return false;
		}

		internal static PlayerDeathHead? Head(PlayerAvatar avatar)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			return (PlayerDeathHead)DeathHead.GetValue(avatar);
		}

		internal static int GetHealth(PlayerHealth health)
		{
			return (int)Health.GetValue(health);
		}

		internal static bool IsShopItem(ItemAttributes attributes)
		{
			return (bool)ShopItem.GetValue(attributes);
		}

		internal static void SetPrice(ItemAttributes attributes, int price)
		{
			ItemValue.SetValue(attributes, price);
		}

		internal static int PlayerId(PlayerAvatar avatar)
		{
			if (!SemiFunc.IsMultiplayer())
			{
				return 1;
			}
			return avatar.photonView.ViewID;
		}

		internal static PlayerAvatar? FindPlayer(int id)
		{
			if (!SemiFunc.IsMultiplayer())
			{
				if (id != 1)
				{
					return null;
				}
				return PlayerAvatar.instance;
			}
			PhotonView val = PhotonView.Find(id);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			return ((Component)val).GetComponent<PlayerAvatar>();
		}

		internal static bool IsLocal(PlayerAvatar avatar)
		{
			if (SemiFunc.IsMultiplayer())
			{
				return avatar.photonView.IsMine;
			}
			return true;
		}

		internal static bool InputAllowed()
		{
			if (Object.op_Implicit((Object)(object)PlayerController.instance))
			{
				return (float)InputDisabled.GetValue(PlayerController.instance) <= 0f;
			}
			return false;
		}

		internal static (Vector3 Position, Vector3 Forward) Aim(PlayerAvatar avatar)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (IsLocal(avatar) && Object.op_Implicit((Object)(object)Camera.main))
			{
				return (Position: ((Component)Camera.main).transform.position, Forward: ((Component)Camera.main).transform.forward);
			}
			Vector3 item = (Vector3)CameraPosition.GetValue(avatar);
			Quaternion val = (Quaternion)CameraRotation.GetValue(avatar);
			return (Position: item, Forward: val * Vector3.forward);
		}
	}
	internal sealed class GameWorld : IRevivalWorld
	{
		private readonly Dictionary<int, long> damage = new Dictionary<int, long>();

		private readonly Dictionary<int, long> lives = new Dictionary<int, long>();

		internal void Damaged(PlayerAvatar player)
		{
			int key = GameAccess.PlayerId(player);
			damage[key] = (damage.TryGetValue(key, out var value) ? (value + 1) : 1);
		}

		internal void Died(PlayerAvatar player)
		{
			int key = GameAccess.PlayerId(player);
			lives[key] = (lives.TryGetValue(key, out var value) ? (value + 1) : 1);
		}

		internal string Life(PlayerAvatar player)
		{
			int key = GameAccess.PlayerId(player);
			long value;
			return ((Object)player).GetInstanceID() + "/" + (lives.TryGetValue(key, out value) ? value : 0);
		}

		public Observation Observe(int actorId, string itemId, int targetActorId)
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: 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_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Invalid comparison between Unknown and I4
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Expected O, but got Unknown
			PlayerAvatar val = GameAccess.FindPlayer(actorId);
			PlayerAvatar val2 = GameAccess.FindPlayer(targetActorId);
			Device device = Device.Active.FirstOrDefault((Device item) => Object.op_Implicit((Object)(object)item) && item.Id == itemId);
			PlayerDeathHead val3 = (Object.op_Implicit((Object)(object)val2) ? GameAccess.Head(val2) : null);
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)val3) || !Object.op_Implicit((Object)(object)device) || !device.Ready)
			{
				return new Observation(false, false, false, false, false, 999.0, 0L, "");
			}
			(Vector3, Vector3) tuple = GameAccess.Aim(val);
			Vector3 val4 = ((Component)val3).transform.position - tuple.Item1;
			float num = Vector3.Dot(val4, tuple.Item2);
			int num2;
			if (num >= 0f)
			{
				Vector3 val5 = val4 - tuple.Item2 * num;
				if (((Vector3)(ref val5)).magnitude <= 0.35f)
				{
					num2 = (ClearRay(tuple.Item1, ((Component)val3).transform.position, val, val3, device) ? 1 : 0);
					goto IL_0110;
				}
			}
			num2 = 0;
			goto IL_0110;
			IL_0110:
			bool flag = (byte)num2 != 0;
			long value;
			return new Observation(Object.op_Implicit((Object)(object)RunManager.instance) && SemiFunc.RunIsLevel() && Object.op_Implicit((Object)(object)GameDirector.instance) && (int)GameDirector.instance.currentState == 2 && !GameAccess.IsShopItem(device.Attributes), GameAccess.IsAlive(val), device.IsHeldBy(val), GameAccess.IsDead(val2) && ((Component)val3).gameObject.activeInHierarchy, flag, (double)((Vector3)(ref val4)).magnitude, damage.TryGetValue(actorId, out value) ? value : 0, Life(val2));
		}

		private static bool ClearRay(Vector3 origin, Vector3 destination, PlayerAvatar player, PlayerDeathHead head, Device device)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: 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_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = destination - origin;
			RaycastHit[] array = Physics.RaycastAll(origin, ((Vector3)(ref val)).normalized, ((Vector3)(ref val)).magnitude, -1, (QueryTriggerInteraction)1);
			for (int i = 0; i < array.Length; i++)
			{
				RaycastHit val2 = array[i];
				Transform transform = ((Component)((RaycastHit)(ref val2)).collider).transform;
				if (!transform.IsChildOf(((Component)player).transform) && !transform.IsChildOf(((Component)device).transform) && !transform.IsChildOf(((Component)head).transform))
				{
					return false;
				}
			}
			return true;
		}

		public bool TryRevive(int actorId, int targetActorId, string targetLifeId, int health)
		{
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return false;
			}
			PlayerAvatar val = GameAccess.FindPlayer(targetActorId);
			if (!Object.op_Implicit((Object)(object)val) || !GameAccess.IsDead(val) || Life(val) != targetLifeId)
			{
				return false;
			}
			PlayerDeathHead val2 = GameAccess.Head(val);
			if (!Object.op_Implicit((Object)(object)val2) || !((Component)val2).gameObject.activeInHierarchy)
			{
				return false;
			}
			val.Revive(false);
			if (GameAccess.IsDead(val))
			{
				return false;
			}
			if (health > 1)
			{
				try
				{
					val.playerHealth.HealOther(health - 1, true);
				}
				catch (Exception ex)
				{
					Plugin.Error("Revival completed, but the additional configured healing failed. " + ex);
				}
			}
			return true;
		}
	}
	internal static class ItemFactory
	{
		internal static Item? Item;

		private static bool failed;

		private static float nextDiscovery;

		private static string lastDiscoveryReport = "";

		internal unsafe static void EnsureRegistered()
		{
			//IL_006a: 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)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Expected O, but got Unknown
			//IL_0158: 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_018d: 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_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Expected O, but got Unknown
			if (Object.op_Implicit((Object)(object)Item) || failed || !Object.op_Implicit((Object)(object)RunManager.instance) || !Object.op_Implicit((Object)(object)StatsManager.instance) || Time.realtimeSinceStartup < nextDiscovery)
			{
				return;
			}
			nextDiscovery = Time.realtimeSinceStartup + 2f;
			GameObject val = null;
			try
			{
				(Item, GameObject, DonorParts)? tuple = FindDonor();
				if (!tuple.HasValue)
				{
					return;
				}
				(Item, GameObject, DonorParts) value = tuple.Value;
				BatteryVisualLogic val2 = null;
				if ((value.Item3 & 0x100) == 0)
				{
					val2 = BatteryDisplayFallback.FindTemplate();
					if (!Object.op_Implicit((Object)(object)val2))
					{
						ReportDiscovery("Compatible tracker found: " + ((Object)value.Item1).name + "; waiting for a self-contained native battery-display template. Enter a lobby/level so the HUD can initialize.");
						return;
					}
				}
				Plugin.LogInfo("Native donor selected: " + ((Object)value.Item1).name + "; components=" + ((object)(*(DonorParts*)(&value.Item3))/*cast due to .constrained prefix*/).ToString());
				val = new GameObject("Defibrillator Prefab Storage");
				val.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)val);
				GameObject val3 = Object.Instantiate<GameObject>(value.Item2, val.transform);
				((Object)val3).name = "Item Industrial Defibrillator";
				ItemAttributes component = val3.GetComponent<ItemAttributes>();
				Item val4 = Object.Instantiate<Item>(value.Item1);
				((Object)val4).name = ((Object)val3).name;
				val4.itemName = "Industrial Defibrillator";
				val4.itemNameLocalized = null;
				val4.description = "Hold Interact while aiming at a dead player's head. Recharge at a charging station.";
				val4.status = (Status)1;
				val4.disabled = false;
				val4.maxAmount = 100;
				val4.maxAmountInShop = 1;
				val4.maxPurchase = false;
				val4.minPlayerCount = 1;
				val4.spawnRotationOffset = Quaternion.identity;
				val4.itemSecretShopType = (itemSecretShopType)0;
				val4.value = ScriptableObject.CreateInstance<Value>();
				val4.value.valueMin = (val4.value.valueMax = (float)Plugin.Instance.Settings.Price * 1000f);
				component.item = val4;
				component.icon = null;
				ItemTracker[] componentsInChildren = val3.GetComponentsInChildren<ItemTracker>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
				}
				ItemToggle component2 = val3.GetComponent<ItemToggle>();
				if (Object.op_Implicit((Object)(object)component2))
				{
					((Behaviour)component2).enabled = false;
					component2.toggleState = false;
					component2.playSound = false;
					component2.onToggle = new UnityEvent();
				}
				ItemBattery component3 = val3.GetComponent<ItemBattery>();
				component3.autoDrain = false;
				component3.batteryActive = false;
				component3.isUnchargable = false;
				if (Object.op_Implicit((Object)(object)val2))
				{
					BatteryDisplayFallback.Attach(val3, val2);
				}
				Light[] componentsInChildren2 = val3.GetComponentsInChildren<Light>(true);
				for (int i = 0; i < componentsInChildren2.Length; i++)
				{
					((Behaviour)componentsInChildren2[i]).enabled = false;
				}
				TMP_Text[] componentsInChildren3 = val3.GetComponentsInChildren<TMP_Text>(true);
				for (int i = 0; i < componentsInChildren3.Length; i++)
				{
					((Behaviour)componentsInChildren3[i]).enabled = false;
				}
				DevicePhysics.ConfigurePrefab(val3);
				OriginalAssets.BuildModel(val3);
				val3.AddComponent<Device>();
				val3.SetActive(true);
				if (Items.RegisterItem(component) == null)
				{
					throw new InvalidOperationException("REPOLib rejected the item prefab.");
				}
				Item = val4;
				Plugin.LogInfo("Registered Industrial Defibrillator using native shell: " + ((Object)value.Item1).name);
			}
			catch (Exception ex)
			{
				failed = true;
				if (Object.op_Implicit((Object)(object)val))
				{
					Object.Destroy((Object)(object)val);
				}
				Plugin.Error("Item registration failed; no replacement of vanilla items was attempted. " + ex);
			}
		}

		private unsafe static (Item Item, GameObject Prefab, DonorParts Parts)? FindDonor()
		{
			//IL_0105: 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_010c: 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_0160: 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_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			string folderPath = StatsManager.instance.folderPath;
			IOrderedEnumerable<Item> orderedEnumerable = (from item in (from item in Resources.LoadAll<Item>(folderPath).Concat(Resources.FindObjectsOfTypeAll<Item>()).Concat(StatsManager.instance.itemDictionary.Values)
					where Object.op_Implicit((Object)(object)item) && item.prefab != null && ((PrefabRef<GameObject>)(object)item.prefab).IsValid() && ((Object)item).name != "Item Industrial Defibrillator"
					select item).Distinct()
				orderby (((Object)item).name.IndexOf("Tracker", StringComparison.OrdinalIgnoreCase) < 0) ? 1 : 0
				select item).ThenBy<Item, string>((Item item) => ((Object)item).name, StringComparer.Ordinal);
			List<string> list = new List<string>();
			(Item, GameObject, DonorParts)? result = null;
			int num = 0;
			foreach (Item item in orderedEnumerable)
			{
				num++;
				try
				{
					GameObject prefab = ((PrefabRef<GameObject>)(object)item.prefab).Prefab;
					if (!Object.op_Implicit((Object)(object)prefab))
					{
						list.Add(((Object)item).name + ": prefab unavailable");
						continue;
					}
					DonorParts val = Parts(item, prefab);
					if (DonorRequirements.IsCompatible(val))
					{
						if ((val & 0x100) != 0)
						{
							return (item, prefab, val);
						}
						(Item, GameObject, DonorParts) valueOrDefault = result.GetValueOrDefault();
						if (!result.HasValue)
						{
							valueOrDefault = (item, prefab, val);
							result = valueOrDefault;
						}
					}
					if ((val & 1) != 0 || ((Object)item).name.IndexOf("Tracker", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						list.Add(((Object)item).name + ": present=" + ((object)(*(DonorParts*)(&val))/*cast due to .constrained prefix*/).ToString() + "; missing=" + ((object)DonorRequirements.Missing(val)/*cast due to .constrained prefix*/).ToString());
					}
				}
				catch (Exception ex)
				{
					list.Add(((Object)item).name + ": load failed: " + ex.GetBaseException().Message);
				}
			}
			if (result.HasValue)
			{
				return result;
			}
			ReportDiscovery("No compatible tracker prefab is available yet. Folder=" + folderPath + "; definitions examined=" + num + ". Candidate report: " + ((list.Count == 0) ? "no tracker components found" : string.Join(" | ", list)));
			return null;
		}

		private static DonorParts Parts(Item definition, GameObject prefab)
		{
			//IL_0001: 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_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: 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_0024: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: 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)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: 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_00bc: 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)
			DonorParts val = (DonorParts)0;
			if (Object.op_Implicit((Object)(object)prefab.GetComponentInChildren<ItemTracker>(true)))
			{
				val = (DonorParts)(val | 1);
			}
			if (Object.op_Implicit((Object)(object)prefab.GetComponent<ItemAttributes>()))
			{
				val = (DonorParts)(val | 2);
			}
			if (Object.op_Implicit((Object)(object)prefab.GetComponent<ItemBattery>()))
			{
				val = (DonorParts)(val | 4);
			}
			if (Object.op_Implicit((Object)(object)prefab.GetComponent<ItemEquippable>()))
			{
				val = (DonorParts)(val | 8);
			}
			if (Object.op_Implicit((Object)(object)prefab.GetComponent<PhysGrabObject>()))
			{
				val = (DonorParts)(val | 0x10);
			}
			if (Object.op_Implicit((Object)(object)prefab.GetComponent<Rigidbody>()))
			{
				val = (DonorParts)(val | 0x20);
			}
			if (Object.op_Implicit((Object)(object)prefab.GetComponent<PhotonView>()))
			{
				val = (DonorParts)(val | 0x40);
			}
			if (Object.op_Implicit((Object)(object)definition.colorPreset))
			{
				val = (DonorParts)(val | 0x80);
			}
			if (Object.op_Implicit((Object)(object)prefab.GetComponentInChildren<BatteryVisualLogic>(true)))
			{
				val = (DonorParts)(val | 0x100);
			}
			if (Object.op_Implicit((Object)(object)prefab.GetComponentInChildren<ItemReviveItem>(true)))
			{
				val = (DonorParts)(val | 0x200);
			}
			return val;
		}

		private static void ReportDiscovery(string report)
		{
			if (!(report == lastDiscoveryReport))
			{
				lastDiscoveryReport = report;
				Plugin.LogInfo("Donor discovery pending: " + report);
			}
		}
	}
	internal sealed class NetworkBridge
	{
		private const string Protocol = "ciriolopipado.defibrillator/3";

		private readonly NetworkedEvent channel;

		internal NetworkBridge()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			channel = new NetworkedEvent("ciriolopipado.defibrillator/3", (Action<EventData>)Receive);
		}

		internal void ResetLocalInput()
		{
			foreach (Device item in Device.Active)
			{
				if (Object.op_Implicit((Object)(object)item) && item.Ready)
				{
					item.ResetInput();
				}
			}
		}

		internal void Send(Device device, int actor, int target, bool release)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.IsMasterClientOrSingleplayer())
			{
				Handle(device, actor, target, release);
				return;
			}
			channel.RaiseEvent((object)new object[5]
			{
				"ciriolopipado.defibrillator/3",
				release ? 1 : 0,
				device.NetworkId,
				actor,
				target
			}, NetworkingEvents.RaiseMasterClient, SendOptions.SendReliable);
		}

		private void Receive(EventData packet)
		{
			//IL_0423: Unknown result type (might be due to invalid IL or missing references)
			//IL_042a: Expected O, but got Unknown
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)Plugin.Instance) || !Plugin.Instance.Operational || !(packet.CustomData is object[] array) || array.Length < 2 || !(array[0] is string text) || text != "ciriolopipado.defibrillator/3" || !(array[1] is int num))
			{
				return;
			}
			try
			{
				switch (num)
				{
				case 3:
					if (array.Length == 13 && PhotonNetwork.MasterClient != null && packet.Sender == PhotonNetwork.MasterClient.ActorNumber && array[2] is int num8 && num8 > 0 && array[3] is float num9 && array[4] is double num10 && array[5] is double num11 && array[6] is double num12 && array[7] is string { Length: <=256 } text3 && array[8] is string { Length: <=64 } text4 && array[9] is int num13 && array[10] is double value && array[11] is double num14 && array[12] is int num15)
					{
						VoiceDebuffs.Receive(num8, new VoiceEffect(num9, num10, num11, num12, text3, text4, num13, (double?)value, num14, num15));
					}
					break;
				case 6:
					if (array.Length == 7 && PhotonNetwork.MasterClient != null && packet.Sender == PhotonNetwork.MasterClient.ActorNumber && array[2] is int num19 && num19 > 0 && array[3] is string { Length: <=64 } text5 && array[4] is int num20 && num20 > 0 && array[5] is int num21 && num21 >= 0 && num21 < 4 && array[6] is double num22 && !double.IsNaN(num22) && !double.IsInfinity(num22))
					{
						VoiceDebuffs.Animal(num19, text5, num20, num21, num22);
					}
					break;
				case 5:
					if (array.Length == 9 && PhotonNetwork.MasterClient != null && packet.Sender == PhotonNetwork.MasterClient.ActorNumber && array[2] is int num3 && num3 > 0 && array[3] is string { Length: <=64 } text2 && array[4] is int num4 && num4 > 0 && array[5] is float num5 && array[6] is float num6 && !float.IsNaN(num5) && !(num5 < 0f) && !(num5 > 10f) && !float.IsNaN(num6) && !(num6 < 0.1f) && !(num6 > 2f) && array[7] is float num7 && !float.IsNaN(num7) && !(Math.Abs(num7) > 180f) && array[8] is bool tumble)
					{
						VoiceDebuffs.Shock(num3, text2, num4, num5, num6, num7, tumble);
					}
					break;
				case 4:
				{
					if (array.Length != 2 || !SemiFunc.IsMasterClientOrSingleplayer())
					{
						break;
					}
					Room currentRoom = PhotonNetwork.CurrentRoom;
					if (((currentRoom != null) ? currentRoom.GetPlayer(packet.Sender, false) : null) == null)
					{
						break;
					}
					RaiseEventOptions val2 = new RaiseEventOptions();
					val2.TargetActors = new int[1] { packet.Sender };
					RaiseEventOptions options = val2;
					{
						foreach (KeyValuePair<int, VoiceEffect> effect in VoiceDebuffs.Effects)
						{
							SendVoice(effect.Key, effect.Value, options);
						}
						break;
					}
				}
				case 2:
				{
					if (array.Length != 7 || PhotonNetwork.MasterClient == null || packet.Sender != PhotonNetwork.MasterClient.ActorNumber)
					{
						break;
					}
					object obj = array[2];
					if (!(obj is int))
					{
						break;
					}
					int id = (int)obj;
					if (array[3] is int operatorId && array[4] is int num16 && array[5] is float num17 && array[6] is int num18 && Enum.IsDefined(typeof(Outcome), num16) && !float.IsNaN(num17) && !float.IsInfinity(num17) && num18 >= 0 && num18 <= 100)
					{
						Device device2 = Device.Active.FirstOrDefault((Device item) => Object.op_Implicit((Object)(object)item) && item.Ready && item.NetworkId == id);
						if (Object.op_Implicit((Object)(object)device2))
						{
							device2.Feedback(operatorId, (Outcome)num16, num17, num18);
						}
					}
					break;
				}
				case 0:
				case 1:
				{
					if (array.Length != 5 || !SemiFunc.IsMasterClientOrSingleplayer())
					{
						break;
					}
					object obj = array[2];
					if (!(obj is int))
					{
						break;
					}
					int itemId = (int)obj;
					if (!(array[3] is int num2) || !(array[4] is int target))
					{
						break;
					}
					PlayerAvatar val = GameAccess.FindPlayer(num2);
					if (Object.op_Implicit((Object)(object)val) && val.photonView.OwnerActorNr == packet.Sender)
					{
						Device device = Device.Active.FirstOrDefault((Device item) => Object.op_Implicit((Object)(object)item) && item.Ready && item.NetworkId == itemId);
						if (Object.op_Implicit((Object)(object)device))
						{
							Handle(device, num2, target, num == 1);
						}
					}
					break;
				}
				}
			}
			catch (Exception ex)
			{
				RevivalService? service = Plugin.Service;
				if (service != null)
				{
					service.CancelAll();
				}
				Plugin.Error("Defibrillator request failed; active revivals cancelled. " + ex);
			}
		}

		private void Handle(Device device, int actor, int target, bool release)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Invalid comparison between Unknown and I4
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Expected I4, but got Unknown
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.Service == null || !device.Ready)
			{
				return;
			}
			device.SyncHostBattery();
			Result val = (release ? Plugin.Service.Release(actor, device.Id) : Plugin.Service.Hold(actor, device.Id, target));
			if ((int)((Result)(ref val)).Outcome == 1)
			{
				device.Battery.SetBatteryLife(((Result)(ref val)).Charge);
				try
				{
					VoiceDebuffs.Revived(target);
				}
				catch (Exception ex)
				{
					Plugin.Error("Revival succeeded, but aftereffects could not be applied. " + ex);
				}
				Plugin.LogInfo("Revival completed: operator=" + actor + ", target=" + target + ", battery=" + ((Result)(ref val)).Charge);
			}
			device.Feedback(actor, ((Result)(ref val)).Outcome, (float)((Result)(ref val)).Progress, ((Result)(ref val)).Charge);
			if (SemiFunc.IsMultiplayer())
			{
				channel.RaiseEvent((object)new object[7]
				{
					"ciriolopipado.defibrillator/3",
					2,
					device.NetworkId,
					actor,
					(int)((Result)(ref val)).Outcome,
					(float)((Result)(ref val)).Progress,
					((Result)(ref val)).Charge
				}, NetworkingEvents.RaiseOthers, SendOptions.SendReliable);
			}
		}

		internal void SendVoice(int target, VoiceEffect effect, RaiseEventOptions? options = null)
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.IsMultiplayer())
			{
				channel.RaiseEvent((object)new object[13]
				{
					"ciriolopipado.defibrillator/3", 3, target, effect.Pitch, effect.VoiceExpiresAt, effect.NextShockAt, effect.ShockInterval, effect.Round, effect.Token, effect.Sequence,
					effect.NextAnimalAt, effect.AnimalInterval, effect.AnimalSequence
				}, options ?? NetworkingEvents.RaiseOthers, SendOptions.SendReliable);
			}
		}

		internal void RequestVoiceSnapshot()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			channel.RaiseEvent((object)new object[2] { "ciriolopipado.defibrillator/3", 4 }, NetworkingEvents.RaiseMasterClient, SendOptions.SendReliable);
		}

		internal void SendShock(int target, string token, int sequence, float strength, float seconds, float yaw, bool tumble)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.IsMultiplayer())
			{
				channel.RaiseEvent((object)new object[9] { "ciriolopipado.defibrillator/3", 5, target, token, sequence, strength, seconds, yaw, tumble }, NetworkingEvents.RaiseOthers, SendOptions.SendReliable);
			}
		}

		internal void SendAnimal(int target, string token, int sequence, int animal, double at)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.IsMultiplayer())
			{
				channel.RaiseEvent((object)new object[7] { "ciriolopipado.defibrillator/3", 6, target, token, sequence, animal, at }, NetworkingEvents.RaiseOthers, SendOptions.SendReliable);
			}
		}
	}
	internal static class OriginalAssets
	{
		private static AudioClip? startCharge;

		private static AudioClip? shock;

		internal static AudioClip StartCharge
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)startCharge))
				{
					return startCharge = Tone("Defibrillator charge", 0.28f, discharge: false);
				}
				return startCharge;
			}
		}

		internal static AudioClip Shock
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)shock))
				{
					return shock = Tone("Defibrillator discharge", 0.45f, discharge: true);
				}
				return shock;
			}
		}

		internal static void BuildModel(GameObject prefab)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_0095: 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_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: 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_017e: 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_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: 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_0289: 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)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_033a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0362: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			//IL_039f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0464: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d4: Unknown result type (might be due to invalid IL or missing references)
			Material val = null;
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if (!Object.op_Implicit((Object)(object)((Component)val2).GetComponentInParent<BatteryVisualLogic>()))
				{
					MeshFilter component = ((Component)val2).GetComponent<MeshFilter>();
					if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.sharedMesh) && val == null)
					{
						val = val2.sharedMaterial;
					}
					val2.enabled = false;
				}
			}
			GameObject val3 = new GameObject("Original Industrial Defibrillator Model");
			val3.layer = prefab.layer;
			val3.transform.SetParent(prefab.transform, false);
			val3.transform.localPosition = Vector3.zero;
			val3.transform.localScale = Vector3.one * 0.5f;
			Material material = Material(new Color(0.83f, 0.3f, 0.055f), val);
			Material val4 = Material(new Color(0.055f, 0.063f, 0.067f), val);
			Material material2 = Material(new Color(0.58f, 0.63f, 0.65f), val);
			Material material3 = Material(new Color(0.02f, 0.16f, 0.15f), val);
			Material material4 = Material(new Color(0.85f, 0.87f, 0.76f), val);
			Material material5 = Material(new Color(0.15f, 0.95f, 0.3f), val);
			Box(val3.transform, "Casing", Vector3.zero, new Vector3(0.48f, 0.28f, 0.21f), material);
			Box(val3.transform, "Lower bumper", new Vector3(0f, -0.14f, 0f), new Vector3(0.51f, 0.035f, 0.24f), val4);
			Box(val3.transform, "Upper bumper", new Vector3(0f, 0.14f, 0f), new Vector3(0.51f, 0.035f, 0.24f), val4);
			Box(val3.transform, "Display", new Vector3(-0.065f, 0.035f, -0.113f), new Vector3(0.24f, 0.12f, 0.012f), material3);
			Box(val3.transform, "Cross horizontal", new Vector3(0.15f, 0.035f, -0.117f), new Vector3(0.085f, 0.023f, 0.012f), material4);
			Box(val3.transform, "Cross vertical", new Vector3(0.15f, 0.035f, -0.119f), new Vector3(0.023f, 0.085f, 0.012f), material4);
			Box(val3.transform, "Handle", new Vector3(0f, 0.23f, 0f), new Vector3(0.22f, 0.032f, 0.05f), val4);
			float[] array = new float[2] { -1f, 1f };
			foreach (float num in array)
			{
				Box(val3.transform, "Handle mount", new Vector3(num * 0.11f, 0.19f, 0f), new Vector3(0.025f, 0.08f, 0.05f), val4);
				Box(val3.transform, "Paddle plate", new Vector3(num * 0.3f, 0f, 0f), new Vector3(0.1f, 0.16f, 0.06f), material2);
				Box(val3.transform, "Paddle grip", new Vector3(num * 0.3f, 0f, -0.055f), new Vector3(0.045f, 0.11f, 0.055f), val4);
				GameObject val5 = new GameObject("Paddle cable")
				{
					layer = prefab.layer
				};
				val5.transform.SetParent(val3.transform, false);
				LineRenderer val6 = val5.AddComponent<LineRenderer>();
				val6.useWorldSpace = false;
				((Renderer)val6).sharedMaterial = val4;
				float startWidth = (val6.endWidth = 0.012f);
				val6.startWidth = startWidth;
				val6.positionCount = 12;
				for (int j = 0; j < 12; j++)
				{
					float num3 = (float)j / 11f;
					val6.SetPosition(j, new Vector3(num * Mathf.Lerp(0.2f, 0.3f, num3), -0.08f - Mathf.Sin(num3 * MathF.PI) * 0.15f, 0.07f));
				}
			}
			for (int k = 0; k < 4; k++)
			{
				Box(val3.transform, "Cell " + k, new Vector3(-0.16f + (float)k * 0.055f, -0.08f, -0.12f), new Vector3(0.037f, 0.025f, 0.012f), material5);
			}
		}

		private static Material Material(Color color, Material? template)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			//IL_0035: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			Shader val = Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard");
			Material val2;
			if (!Object.op_Implicit((Object)(object)val))
			{
				if (!Object.op_Implicit((Object)(object)template))
				{
					throw new InvalidOperationException("No supported model shader available.");
				}
				val2 = new Material(template);
			}
			else
			{
				val2 = new Material(val);
			}
			Material val3 = val2;
			((Object)val3).name = "Defibrillator original material";
			if (val3.HasProperty("_Color"))
			{
				val3.SetColor("_Color", color);
			}
			if (val3.HasProperty("_BaseColor"))
			{
				val3.SetColor("_BaseColor", color);
			}
			return val3;
		}

		private static void Box(Transform parent, string name, Vector3 position, Vector3 scale, Material material)
		{
			//IL_002b: 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)
			GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3);
			((Object)obj).name = name;
			Object.DestroyImmediate((Object)(object)obj.GetComponent<Collider>());
			obj.transform.SetParent(parent, false);
			obj.transform.localPosition = position;
			obj.transform.localScale = scale;
			obj.GetComponent<Renderer>().sharedMaterial = material;
			obj.layer = ((Component)parent).gameObject.layer;
		}

		private static AudioClip Tone(string name, float duration, bool discharge)
		{
			float[] array = new float[(int)(44100f * duration)];
			uint num = 173u;
			double num2 = 0.0;
			for (int i = 0; i < array.Length; i++)
			{
				double num3 = (double)i / 44100.0;
				double num4 = num3 / (double)duration;
				double num5 = (discharge ? (180.0 * Math.Exp(-5.0 * num4) + 65.0) : (600.0 + num4 * 1500.0));
				num2 += Math.PI * 2.0 * num5 / 44100.0;
				num = num * 1664525 + 1013904223;
				double num6 = (double)num / 4294967295.0 * 2.0 - 1.0;
				double num7 = Math.Min(1.0, num3 / 0.008) * Math.Pow(1.0 - num4, discharge ? 3.0 : 0.7);
				array[i] = (float)(num7 * (Math.Sin(num2) * 0.45 + (discharge ? (num6 * 0.3) : 0.0)));
			}
			AudioClip obj = AudioClip.Create(name, array.Length, 1, 44100, false);
			obj.SetData(array, 0);
			return obj;
		}
	}
	[HarmonyPatch(typeof(StatsManager), "LoadItemsFromFolder")]
	internal static class RegisterPatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			ItemFactory.EnsureRegistered();
		}
	}
	[HarmonyPatch(typeof(ItemAttributes), "GetValue")]
	internal static class PricePatch
	{
		[HarmonyPrefix]
		private static bool Prefix(ItemAttributes __instance)
		{
			if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<Device>()))
			{
				return true;
			}
			if (SemiFunc.IsMasterClientOrSingleplayer())
			{
				int price = Plugin.Instance.Settings.Price;
				GameAccess.SetPrice(__instance, price);
				PhotonView component = ((Component)__instance).GetComponent<PhotonView>();
				if (SemiFunc.IsMultiplayer() && component.ViewID != 0)
				{
					component.RPC("GetValueRPC", (RpcTarget)1, new object[1] { price });
				}
			}
			return false;
		}
	}
	[HarmonyPatch]
	internal static class ShopPatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.GetDeclaredMethods(typeof(PunManager)).Single((MethodInfo method) => method.Name == "ShopPopulateItemVolumes" && method.GetParameters().Length == 1);
		}

		[HarmonyPrefix]
		[HarmonyPriority(0)]
		private static void Prefix(PunManager __instance, object[] __args)
		{
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: 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)
			if (!SemiFunc.IsMasterClientOrSingleplayer() || !Object.op_Implicit((Object)(object)ShopManager.instance))
			{
				return;
			}
			ItemFactory.EnsureRegistered();
			Item item = ItemFactory.Item;
			if (!Object.op_Implicit((Object)(object)item))
			{
				return;
			}
			ShopManager instance = ShopManager.instance;
			instance.potentialItems.RemoveAll((Item candidate) => (Object)(object)candidate == (Object)(object)item);
			instance.potentialItemConsumables.RemoveAll((Item candidate) => (Object)(object)candidate == (Object)(object)item);
			instance.potentialItemUpgrades.RemoveAll((Item candidate) => (Object)(object)candidate == (Object)(object)item);
			instance.potentialItemHealthPacks.RemoveAll((Item candidate) => (Object)(object)candidate == (Object)(object)item);
			ItemVolume val = ((IEnumerable<ItemVolume>)instance.itemVolumes).FirstOrDefault((Func<ItemVolume, bool>)((ItemVolume candidate) => Object.op_Implicit((Object)(object)candidate) && candidate.itemVolume == item.itemVolume)) ?? ((IEnumerable<ItemVolume>)instance.itemVolumes).FirstOrDefault((Func<ItemVolume, bool>)((ItemVolume candidate) => Object.op_Implicit((Object)(object)candidate)));
			if (!Object.op_Implicit((Object)(object)val))
			{
				Plugin.Error("No shop slot available for the guaranteed defibrillator.");
				return;
			}
			itemVolume itemVolume = val.itemVolume;
			try
			{
				val.itemVolume = item.itemVolume;
				object[] parameters = new object[5]
				{
					val,
					new List<Item> { item },
					0,
					false,
					__args[0]
				};
				if (!(bool)AccessTools.Method(typeof(PunManager), "SpawnShopItem", (Type[])null, (Type[])null).Invoke(__instance, parameters))
				{
					Plugin.Error("Failed to reserve the defibrillator shop slot.");
					return;
				}
				instance.itemVolumes.Remove(val);
				Object.Destroy((Object)(object)((Component)val).gameObject);
				Plugin.LogInfo("Reserved one defibrillator shop slot at price " + Plugin.Instance.Settings.Price + ".");
			}
			catch (Exception ex)
			{
				Plugin.Error("Defibrillator shop injection failed. " + ex);
			}
			finally
			{
				val.itemVolume = itemVolume;
			}
		}
	}
	[HarmonyPatch(typeof(PlayerHealth), "Hurt")]
	internal static class LocalDamagePatch
	{
		[HarmonyPrefix]
		private static void Prefix(PlayerHealth __instance, out int __state)
		{
			__state = GameAccess.GetHealth(__instance);
		}

		[HarmonyPostfix]
		private static void Postfix(PlayerHealth __instance, int __state)
		{
			if (GameAccess.GetHealth(__instance) < __state)
			{
				PlayerAvatar componentInParent = ((Component)__instance).GetComponentInParent<PlayerAvatar>();
				if (Object.op_Implicit((Object)(object)componentInParent))
				{
					Plugin.World.Damaged(componentInParent);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerHealth), "UpdateHealthRPC")]
	internal static class RemoteDamagePatch
	{
		[HarmonyPrefix]
		private static void Prefix(PlayerHealth __instance, out int __state)
		{
			__state = GameAccess.GetHealth(__instance);
		}

		[HarmonyPostfix]
		private static void Postfix(PlayerHealth __instance, int __state)
		{
			if (GameAccess.GetHealth(__instance) < __state)
			{
				PlayerAvatar componentInParent = ((Component)__instance).GetComponentInParent<PlayerAvatar>();
				if (Object.op_Implicit((Object)(object)componentInParent))
				{
					Plugin.World.Damaged(componentInParent);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerAvatar), "PlayerDeathDone")]
	internal static class DeathPatch
	{
		[HarmonyPrefix]
		private static void Prefix(PlayerAvatar __instance, out bool __state)
		{
			__state = GameAccess.IsDead(__instance);
		}

		[HarmonyPostfix]
		private static void Postfix(PlayerAvatar __instance, bool __state)
		{
			if (!__state && GameAccess.IsDead(__instance))
			{
				Plugin.World.Died(__instance);
				VoiceDebuffs.ClearPlayer(GameAccess.PlayerId(__instance));
			}
		}
	}
	[BepInPlugin("ciriolopipado.defibrillator", "Industrial Defibrillator", "0.1.5")]
	[BepInDependency("REPOLib", "4.3.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Id = "ciriolopipado.defibrillator";

		public const string Version = "0.1.5";

		internal static Plugin Instance = null;

		internal Settings Settings;

		internal NetworkBridge Network;

		private Harmony? harmony;

		private bool failed;

		private bool wasHost;

		internal static RevivalService? Service;

		internal static readonly GameWorld World = new GameWorld();

		internal bool Operational => !failed;

		private void Awake()
		{
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Expected O, but got Unknown
			//IL_055d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0567: Expected O, but got Unknown
			Instance = this;
			try
			{
				ConfigEntry<int> val = ((BaseUnityPlugin)this).Config.Bind<int>("Shop", "Price", 2, "Host setting: price in displayed shop currency units; 2 means 2k.");
				ConfigEntry<int> val2 = ((BaseUnityPlugin)this).Config.Bind<int>("Battery", "CostPercent", 50, "Host setting: percent spent per successful revival, 1–100. Default 50 gives two uses per charge.");
				ConfigEntry<int> val3 = ((BaseUnityPlugin)this).Config.Bind<int>("Internal", "BalanceRevision", 0, "One-time migration of legacy free-price / four-use test defaults. Keep this value after upgrading.");
				if (val3.Value < 1)
				{
					(int, int) tuple = BalanceMigration.Apply(val3.Value, val.Value, val2.Value);
					val.Value = tuple.Item1;
					val2.Value = tuple.Item2;
					val3.Value = 1;
					((BaseUnityPlugin)this).Config.Save();
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Balance defaults migrated: Price=" + val.Value + ", CostPercent=" + val2.Value + ". Custom values were preserved."));
				}
				Settings = new Settings(((BaseUnityPlugin)this).Config.Bind<double>("Revival", "HoldSeconds", 3.0, "Host setting: hold duration, 0.25–30 seconds.").Value, ((BaseUnityPlugin)this).Config.Bind<double>("Revival", "RangeMeters", 2.0, "Host setting: maximum eye-to-head distance, up to 10 meters.").Value, ((BaseUnityPlugin)this).Config.Bind<int>("Revival", "Health", 1, "Host setting: health after revival, 1–100.").Value, val2.Value, val.Value, 0.75);
				GameAccess.Validate();
				VoiceDebuffs.Seconds = ((BaseUnityPlugin)this).Config.Bind<double>("VoiceDebuff", "Seconds", 180.0, "Maximum duration, 1–3600 seconds; also ends at death or level end.").Value;
				VoiceDebuffs.HighPitch = ((BaseUnityPlugin)this).Config.Bind<float>("VoiceDebuff", "HighPitch", 1.8f, "Comically high voice multiplier, above 1 and up to 2.").Value;
				VoiceDebuffs.LowPitch = ((BaseUnityPlugin)this).Config.Bind<float>("VoiceDebuff", "LowPitch", 0.55f, "Comically low voice multiplier, at least 0.5 and below 1.").Value;
				VoiceDebuffs.ShockInterval = ((BaseUnityPlugin)this).Config.Bind<double>("Aftershock", "IntervalSeconds", 30.0, "Harmless shock interval, 5–300 seconds; ends at death or level end.").Value;
				ConfigEntry<float> val4 = ((BaseUnityPlugin)this).Config.Bind<float>("Aftershock", "CameraShakeStrength", 7f, "Camera shake strength, 0–10; respects native camera-shake settings.");
				ConfigEntry<float> val5 = ((BaseUnityPlugin)this).Config.Bind<float>("Aftershock", "CameraShakeSeconds", 1.2f, "Camera shake duration, 0.1–2 seconds.");
				ConfigEntry<int> val6 = ((BaseUnityPlugin)this).Config.Bind<int>("Internal", "AftershockRevision", 0, "Once-only upgrade of old weak shake defaults.");
				if (val6.Value < 1)
				{
					(float, float) tuple2 = AftershockImpact.UpgradeLegacy(val6.Value, val4.Value, val5.Value);
					val4.Value = tuple2.Item1;
					val5.Value = tuple2.Item2;
					val6.Value = 1;
					((BaseUnityPlugin)this).Config.Save();
				}
				VoiceDebuffs.ShakeStrength = val4.Value;
				VoiceDebuffs.ShakeSeconds = val5.Value;
				VoiceDebuffs.YawDegrees = ((BaseUnityPlugin)this).Config.Bind<float>("Aftershock", "YawDegrees", 180f, "Horizontal turn per shock, 0–180 degrees; random left/right. Set 0 to disable turning.").Value;
				VoiceDebuffs.TumbleChance = ((BaseUnityPlugin)this).Config.Bind<double>("Aftershock", "TumbleChance", 0.25, "Probability of native Q/tumble per shock, 0–1; 0 disables, 1 always triggers.").Value;
				AftershockImpact.YawAt(VoiceDebuffs.YawDegrees, 0.0);
				AftershockImpact.RollTumble(0.0, VoiceDebuffs.TumbleChance);
				VoiceDebuffs.AnimalEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("AnimalVoice", "Enabled", true, "Host setting: emit a random animal sound automatically after revival.").Value;
				VoiceDebuffs.AnimalInterval = ((BaseUnityPlugin)this).Config.Bind<double>("AnimalVoice", "IntervalSeconds", 30.0, "Host setting: animal interval, 5–300 seconds; independent of electrical shocks.").Value;
				VoiceDebuffs.AnimalVolume = ((BaseUnityPlugin)this).Config.Bind<float>("AnimalVoice", "Volume", 0.7f, "Local playback volume, 0–1. Per-player voice gain and the voice mixer also apply.").Value;
				if (double.IsNaN(VoiceDebuffs.AnimalInterval) || double.IsInfinity(VoiceDebuffs.AnimalInterval) || VoiceDebuffs.AnimalInterval < 5.0 || VoiceDebuffs.AnimalInterval > 300.0 || float.IsNaN(VoiceDebuffs.AnimalVolume) || VoiceDebuffs.AnimalVolume < 0f || VoiceDebuffs.AnimalVolume > 1f)
				{
					throw new ArgumentException("Invalid animal voice settings.");
				}
				VoiceEffect.ChoosePitch(0, VoiceDebuffs.HighPitch, VoiceDebuffs.LowPitch);
				if (double.IsNaN(VoiceDebuffs.Seconds) || double.IsInfinity(VoiceDebuffs.Seconds) || VoiceDebuffs.Seconds < 1.0 || VoiceDebuffs.Seconds > 3600.0 || double.IsNaN(VoiceDebuffs.ShockInterval) || double.IsInfinity(VoiceDebuffs.ShockInterval) || VoiceDebuffs.ShockInterval < 5.0 || VoiceDebuffs.ShockInterval > 300.0 || float.IsNaN(VoiceDebuffs.ShakeStrength) || VoiceDebuffs.ShakeStrength < 0f || VoiceDebuffs.ShakeStrength > 10f || float.IsNaN(VoiceDebuffs.ShakeSeconds) || VoiceDebuffs.ShakeSeconds < 0.1f || VoiceDebuffs.ShakeSeconds > 2f)
				{
					throw new ArgumentException("Invalid voice debuff duration settings.");
				}
				AnimalClips.Load();
				Network = new NetworkBridge();
				harmony = new Harmony("ciriolopipado.defibrillator");
				harmony.PatchAll(typeof(Plugin).Assembly);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Industrial Defibrillator 0.1.5 loaded. Target: R.E.P.O. 0.5.1 / REPOLib 4.3.0. In-game validation required.");
			}
			catch (Exception ex)
			{
				failed = true;
				Harmony? obj = harmony;
				if (obj != null)
				{
					obj.UnpatchSelf();
				}
				((BaseUnityPlugin)this).Logger.LogError((object)("Defibrillator initialization failed; features disabled. " + ex));
			}
		}

		private void Update()
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if (failed || !Object.op_Implicit((Object)(object)RunManager.instance) || !Object.op_Implicit((Object)(object)GameManager.instance))
			{
				return;
			}
			try
			{
				ItemFactory.EnsureRegistered();
				VoiceDebuffs.Tick();
				bool flag = SemiFunc.IsMasterClientOrSingleplayer();
				if (flag != wasHost || (flag && Service == null))
				{
					RevivalService? service = Service;
					if (service != null)
					{
						service.CancelAll();
					}
					Service = ((!flag) ? ((RevivalService)null) : new RevivalService(Settings, (IRevivalWorld)(object)World, (Func<double>)(() => Time.realtimeSinceStartupAsDouble)));
					wasHost = flag;
					Network.ResetLocalInput();
				}
				if (!flag)
				{
					return;
				}
				foreach (Device item in Device.Active)
				{
					if (Object.op_Implicit((Object)(object)item) && item.Ready)
					{
						item.SyncHostBattery();
					}
				}
				RevivalService? service2 = Service;
				if (service2 != null)
				{
					service2.Tick();
				}
			}
			catch (Exception ex)
			{
				failed = true;
				RevivalService? service3 = Service;
				if (service3 != null)
				{
					service3.CancelAll();
				}
				Service = null;
				((BaseUnityPlugin)this).Logger.LogError((object)("Defibrillator stopped after an unexpected runtime error. Restart the lobby and report this log. " + ex));
			}
		}

		private void OnDestroy()
		{
			failed = true;
			AnimalVoicePlayback.StopAll();
			RevivalService? service = Service;
			if (service != null)
			{
				service.CancelAll();
			}
			Service = null;
			Harmony? obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}

		internal static void LogInfo(string message)
		{
			((BaseUnityPlugin)Instance).Logger.LogInfo((object)message);
		}

		internal static void Error(string message)
		{
			((BaseUnityPlugin)Instance).Logger.LogError((object)message);
		}
	}
	internal static class VoiceDebuffs
	{
		internal static readonly Dictionary<int, VoiceEffect> Effects = new Dictionary<int, VoiceEffect>();

		private static readonly Dictionary<string, int> seenPulses = new Dictionary<string, int>();

		private static readonly HashSet<string> endedTokens = new HashSet<string>();

		private static readonly Dictionary<string, int> seenAnimals = new Dictionary<string, int>();

		internal static bool AnimalEnabled;

		internal static double AnimalInterval;

		internal static float AnimalVolume;

		internal static double Seconds;

		internal static float HighPitch;

		internal static float LowPitch;

		internal static double ShockInterval;

		internal static float ShakeStrength;

		internal static float ShakeSeconds;

		internal static float YawDegrees;

		internal static double TumbleChance;

		private static float nextSnapshotRequest;

		private static object? previousRoom;

		private static readonly FieldInfo VoicePlayer = AccessTools.Field(typeof(PlayerVoiceChat), "playerAvatar") ?? throw new MissingFieldException("PlayerVoiceChat.playerAvatar");

		internal static double Now
		{
			get
			{
				if (!SemiFunc.IsMultiplayer())
				{
					return Time.realtimeSinceStartupAsDouble;
				}
				return PhotonNetwork.Time;
			}
		}

		internal static string Round => ((Object)RunManager.instance.levelCurrent).name + "/" + RunManager.instance.levelsCompleted;

		internal static void Revived(int target)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			if (SemiFunc.IsMasterClientOrSingleplayer())
			{
				EnsureRoom();
				VoiceEffect val = new VoiceEffect(VoiceEffect.ChoosePitch(Random.Range(0, 2), HighPitch, LowPitch), Now + Seconds, Now + ShockInterval, ShockInterval, Round, Guid.NewGuid().ToString("N"), 0, (double?)(Now + AnimalInterval), AnimalInterval, 0);
				Effects[target] = val;
				seenPulses[val.Token] = 0;
				seenAnimals[val.Token] = 0;
				Plugin.Instance.Network.SendVoice(target, val);
				Plugin.LogInfo("Revival aftereffects applied: target=" + target + ", pitch=" + val.Pitch + ", voiceSeconds=" + Seconds);
			}
		}

		internal static void Tick()
		{
			EnsureRoom();
			if (!SemiFunc.RunIsLevel())
			{
				AnimalVoicePlayback.StopAll();
				Effects.Clear();
				seenPulses.Clear();
				seenAnimals.Clear();
				endedTokens.Clear();
				return;
			}
			KeyValuePair<int, VoiceEffect>[] array = Effects.ToArray();
			for (int i = 0; i < array.Length; i++)
			{
				KeyValuePair<int, VoiceEffect> keyValuePair = array[i];
				PlayerAvatar val = GameAccess.FindPlayer(keyValuePair.Key);
				if (!Object.op_Implicit((Object)(object)val))
				{
					Effects.Remove(keyValuePair.Key);
					seenPulses.Remove(keyValuePair.Value.Token);
					continue;
				}
				if (!keyValuePair.Value.IsActive(Now, Round, GameAccess.IsAlive(val)))
				{
					ClearPlayer(keyValuePair.Key);
					continue;
				}
				if (SemiFunc.IsMasterClientOrSingleplayer() && keyValuePair.Value.TryShock(Now, Round, true))
				{
					float yaw = YawDegrees * (float)((Random.Range(0, 2) != 0) ? 1 : (-1));
					bool tumble = AftershockImpact.RollTumble((double)Random.Range(0, 1000000) / 1000000.0, TumbleChance);
					Shock(keyValuePair.Key, keyValuePair.Value.Token, keyValuePair.Value.Sequence, ShakeStrength, ShakeSeconds, yaw, tumble);
					Plugin.Instance.Network.SendShock(keyValuePair.Key, keyValuePair.Value.Token, keyValuePair.Value.Sequence, ShakeStrength, ShakeSeconds, yaw, tumble);
				}
				if (SemiFunc.IsMasterClientOrSingleplayer() && AnimalEnabled && AnimalClips.Ready && keyValuePair.Value.TryAnimal(Now, Round, true))
				{
					int animal = Random.Range(0, 4);
					double now = Now;
					Animal(keyValuePair.Key, keyValuePair.Value.Token, keyValuePair.Value.AnimalSequence, animal, now);
					Plugin.Instance.Network.SendAnimal(keyValuePair.Key, keyValuePair.Value.Token, keyValuePair.Value.AnimalSequence, animal, now);
				}
			}
			if (SemiFunc.IsMultiplayer() && !PhotonNetwork.IsMasterClient && Time.unscaledTime >= nextSnapshotRequest)
			{
				nextSnapshotRequest = Time.unscaledTime + 3f;
				Plugin.Instance.Network.RequestVoiceSnapshot();
			}
		}

		private static void EnsureRoom()
		{
			object currentRoom = PhotonNetwork.CurrentRoom;
			if (currentRoom != previousRoom)
			{
				AnimalVoicePlayback.StopAll();
				Effects.Clear();
				seenPulses.Clear();
				seenAnimals.Clear();
				endedTokens.Clear();
				previousRoom = currentRoom;
				nextSnapshotRequest = 0f;
			}
		}

		internal static void ClearPlayer(int target)
		{
			if (Effects.TryGetValue(target, out VoiceEffect value))
			{
				Effects.Remove(target);
				AnimalVoicePlayback.Stop(target);
				seenPulses.Remove(value.Token);
				seenAnimals.Remove(value.Token);
				endedTokens.Add(value.Token);
			}
		}

		internal static void Receive(int target, VoiceEffect effect)
		{
			EnsureRoom();
			if (Object.op_Implicit((Object)(object)RunManager.instance) && SemiFunc.RunIsLevel() && !(effect.Round != Round) && !endedTokens.Contains(effect.Token))
			{
				if (Effects.TryGetValue(target, out VoiceEffect value) && value.Token != effect.Token)
				{
					seenPulses.Remove(value.Token);
				}
				Effects[target] = effect;
				seenPulses[effect.Token] = Math.Max(effect.Sequence, seenPulses.TryGetValue(effect.Token, out var value2) ? value2 : 0);
				seenAnimals[effect.Token] = Math.Max(effect.AnimalSequence, seenAnimals.TryGetValue(effect.Token, out var value3) ? value3 : 0);
			}
		}

		internal static void Animal(int target, string token, int sequence, int animal, double at)
		{
			if (AnimalClips.Ready && animal >= 0 && animal < 4 && sequence > 0 && Effects.TryGetValue(target, out VoiceEffect value) && !(value.Token != token) && (!seenAnimals.TryGetValue(token, out var value2) || sequence > value2))
			{
				PlayerAvatar val = GameAccess.FindPlayer(target);
				if (Object.op_Implicit((Object)(object)val) && value.IsActive(Now, Round, GameAccess.IsAlive(val)))
				{
					seenAnimals[token] = sequence;
					AnimalVoicePlayback.Play(target, token, animal, at);
				}
			}
		}

		internal static void Shock(int target, string token, int sequence, float strength, float seconds, float yaw, bool tumble)
		{
			if (!Effects.TryGetValue(target, out VoiceEffect value) || value.Token != token || (seenPulses.TryGetValue(token, out var value2) && sequence <= value2))
			{
				return;
			}
			PlayerAvatar val = GameAccess.FindPlayer(target);
			if (!Object.op_Implicit((Object)(object)val) || !value.IsActive(Now, Round, GameAccess.IsAlive(val)))
			{
				return;
			}
			seenPulses[token] = sequence;
			AftershockVisual.Spawn(val, sequence, strength, seconds);
			AftershockCamera.Spawn(val, yaw, seconds);
			if (tumble && SemiFunc.IsMasterClientOrSingleplayer() && !GameAccess.IsTumbling(val))
			{
				PlayerTumble val2 = GameAccess.Tumble(val);
				if (Object.op_Implicit((Object)(object)val2))
				{
					val2.TumbleSet(true, false, false);
				}
			}
		}

		internal static void Apply(PlayerVoiceChat voice)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			if (Object.op_Implicit((Object)(object)Plugin.Instance) && Plugin.Instance.Operational && Object.op_Implicit((Object)(object)RunManager.instance) && SemiFunc.RunIsLevel())
			{
				PlayerAvatar val = (PlayerAvatar)VoicePlayer.GetValue(voice);
				if (Object.op_Implicit((Object)(object)val) && Effects.TryGetValue(GameAccess.PlayerId(val), out VoiceEffect value) && value.HasVoice(Now, Round, GameAccess.IsAlive(val)))
				{
					voice.OverridePitch(value.Pitch, 0.12f, 0.2f, 0.3f, 0f, 0f);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerVoiceChat), "Update")]
	internal static class VoicePatch
	{
		[HarmonyPrefix]
		private static void Prefix(PlayerVoiceChat __instance)
		{
			AnimalVoicePlayback.BeforeVoice(__instance);
			VoiceDebuffs.Apply(__instance);
		}

		[HarmonyPostfix]
		private static void Postfix(PlayerVoiceChat __instance)
		{
			AnimalVoicePlayback.AfterVoice(__instance);
		}
	}
}