Decompiled source of Everything is Multiplayer v0.6.8

BepInEx\plugins\Everything_is_Multiplayer.dll

Decompiled 12 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using MoreMountains.Tools;
using MoreMountains.TopDownEngine;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using World;
using World.AI;
using World.AI.PreventBeingAttackedOnSight;
using World.Burrows;
using World.Characters;
using World.Characters.Bosses;
using World.Characters.Enemies.Navigation;
using World.CustomTDEAbilities;
using World.Evolutions;
using World.Evolutions.Abilities.Attacks;
using World.Evolutions.Abilities.Dashes;
using World.Evolutions.Specializations;
using World.Evolutions.UI;
using World.HeatAndCold;
using World.Items;
using World.Mushrooms;
using World.Mushrooms.Effects;
using World.Stats;
using World.Stats.StatValueTypes;
using World.TimeManagement;
using World.UI;
using World.UI.HUD;
using World.UI.MainMenuScreen;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Everything_is_Multiplayer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+24fd158a5b1ed61a4eaa20c2f65c0bde0a4af2de")]
[assembly: AssemblyProduct("Everything_is_Multiplayer")]
[assembly: AssemblyTitle("Everything_is_Multiplayer")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Everything_is_Multiplayer
{
	public sealed class LocalMultiplayerDriver : MonoBehaviour
	{
		private sealed class NightVisionMaterialState
		{
			public Material Material;

			public Vector4 BaseCenter;

			public float BaseViewportRadius;

			public float BaseGradientRadius;

			public Vector4 LastAppliedCenter = new Vector4(float.NaN, float.NaN, float.NaN, float.NaN);

			public float LastAppliedViewportRadius = float.NaN;

			public float LastAppliedGradientRadius = float.NaN;
		}

		private const string PlayerTwoName = "LocalMultiplayer_Player2";

		private const string PlayerOnePendingDestroyName = "LocalMultiplayer_Player1_PendingDestroy";

		private const string PlayerOneLabelName = "LocalMultiplayer_Player1_Label";

		private const string PlayerTwoLabelName = "LocalMultiplayer_Player2_Label";

		private static readonly Color PlayerOneLabelColor = new Color(0.56f, 0.95f, 0.65f, 1f);

		private static readonly Color PlayerTwoTint = new Color(0.55f, 0.9f, 1f, 1f);

		private int _sceneHandle;

		private int _playerOneId;

		private int _playerTwoId;

		private int _cameraId;

		private int _lastGamepadCount = -1;

		private float _baseOrthographicSize;

		private float _smoothedOrthographicSize;

		private Vector2 _smoothedCameraCenter;

		private bool _hasSharedCameraState;

		private int _cameraEnforcerId;

		private readonly Dictionary<int, NightVisionMaterialState> _nightVisionMaterialStates = new Dictionary<int, NightVisionMaterialState>();

		private bool _previousDashHeld;

		private bool _previousInteractHeld;

		private bool _loggedPlayerTwoInput;

		private bool _loggedFilteredStockInput;

		private bool _loggedGameplaySpawnFallback;

		private bool _loggedPlayerTwoDamageAttempt;

		private bool _loggedPlayerTwoDamageOutputOverride;

		private bool _loggedPlayerTwoMasterHealthCleared;

		private bool _loggedPlayerTwoColliderState;

		private bool _loggedPlayerTwoPhysicalColliderEnabled;

		private bool _loggedPlayerTwoRigidbodyEnabled;

		private bool _loggedPlayerTwoDamageOnTouchCollision;

		private bool _loggedPlayerTwoDamageOnTouchMaskPatched;

		private bool _loggedPlayerTwoDamageOnTouchIgnoreCleared;

		private bool _loggedPlayerTwoDamageOnTouchFallback;

		private bool _loggedPlayerTwoAiIgnoreCleared;

		private bool _loggedPlayerTwoDirectAiRegistration;

		private bool _loggedPlayerTwoDirectAiRegistrationFailure;

		private bool _loggedPlayerTwoAttackScoreForced;

		private bool _loggedPlayerTwoTargetConsidered;

		private bool _loggedPlayerTwoPreventSightBypass;

		private bool _loggedFriendlyFireSuppressed;

		private int _playerTwoDamageResultLogs;

		private bool _playerOneDead;

		private bool _playerOneAwaitingRevive;

		private bool _playerTwoDead;

		private bool _playerTwoAwaitingRevive;

		private string _playerOneObjectName = "PlayerCharacter";

		private readonly List<Color> _playerOneSpriteColors = new List<Color>();

		private bool _evolutionPickerOpen;

		private int _suppressedPlayerDeathDropCount;

		private bool _previousDumpStateHeld;

		private bool _previousRespawnHeld;

		private bool _previousForceSpawnHeld;

		private bool _previousDamagePlayerTwoHeld;

		private bool _previousDamagePlayerOneHeld;

		private readonly bool[] _previousAttackHeld = new bool[5];

		private float _nextSpawnAttemptAt;

		private float _nextStatusLogAt;

		private float _nextSpawnWaitLogAt;

		private float _nextAiRefreshAt;

		private int _damageOnTouchStateKey;

		private Health _damageOnTouchStateHealth;

		private GameObject _damageOnTouchStateInstigator;

		private float _damageOnTouchStateBeforeHealth;

		private float _damageOnTouchStateFallbackDamage;

		private float _damageOnTouchStateInvincibilityDuration;

		private int _damageOnTouchStateContextualDeathTip;

		private string _damageOnTouchStateSourceName = string.Empty;

		private string _lastSpawnWaitReason = string.Empty;

		private string _playerTwoDamageHudStatus = "P2 DMG: WAIT";

		private string _playerTwoAiHudStatus = "P2 AI: WAIT";

		private string _cameraHudStatus = "CAM: WAIT";

		private bool _debugPlayerOneInputOverride;

		private bool _applyingDiagnosticDamage;

		private Action<ScriptableRenderContext, Camera> _beginCameraRenderingHandler;

		private bool _debugPlayerTwoInputOverride;

		private int _debugPlayerOneGamepadIndex = -1;

		private int _debugPlayerTwoGamepadIndex = -1;

		private Vector2 _debugPlayerOneMove;

		private Vector2 _debugPlayerOneAim = Vector2.right;

		private Vector2 _debugPlayerTwoMove;

		private Vector2 _debugPlayerTwoAim = Vector2.right;

		private bool _debugPlayerTwoDashHeld;

		private bool _debugPlayerTwoInteractHeld;

		private readonly bool[] _debugPlayerTwoAttackHeld = new bool[5];

		private Vector2 _playerOneMove;

		private Vector2 _playerOneAim = Vector2.right;

		private bool _playerOneAimControlled;

		private float _lastPlayerTwoSizePercentage = float.NaN;

		private int _mushroomManagerId;

		private List<MushroomImpactStateInfo> _playerOneMushroomEffects;

		private List<MushroomImpactStateInfo> _playerTwoMushroomEffects;

		private List<MushroomImpactStateInfo> _mushroomEffectsBeforeConsumption;

		private int _mushroomConsumptionRoutingDepth;

		private PlayerCharacter _mushroomConsumerPreviousSingleton;

		private int _mushroomConsumerSingletonDepth;

		private bool _updatingOwnedMushroomEffects;

		private int _lastMushroomEffectUpdatePlayerNumber;

		public static LocalMultiplayerDriver Instance { get; private set; }

		public PlayerCharacter PlayerOne { get; private set; }

		public PlayerCharacter PlayerTwo { get; private set; }

		public PlayerTwoInputState InputState { get; private set; }

		public Vector2 PlayerOneMoveInput => _playerOneMove;

		public int PlayerOneMushroomEffectCount => _playerOneMushroomEffects?.Count ?? 0;

		public int PlayerTwoMushroomEffectCount => _playerTwoMushroomEffects?.Count ?? 0;

		public int LastMushroomEffectUpdatePlayerNumber => _lastMushroomEffectUpdatePlayerNumber;

		public bool IsPlayerOneDead
		{
			get
			{
				if (!_playerOneAwaitingRevive && !_playerOneDead)
				{
					return IsDead(PlayerOne);
				}
				return true;
			}
		}

		public bool IsPlayerOneRemoved
		{
			get
			{
				if (_playerOneDead)
				{
					return (Object)(object)PlayerOne == (Object)null;
				}
				return false;
			}
		}

		public bool IsPlayerOneAwaitingRevive => _playerOneAwaitingRevive;

		public bool IsPlayerTwoDead
		{
			get
			{
				if (!_playerTwoAwaitingRevive && !_playerTwoDead)
				{
					return IsDead(PlayerTwo);
				}
				return true;
			}
		}

		public bool IsPlayerTwoAwaitingRevive => _playerTwoAwaitingRevive;

		public bool IsEvolutionPickerOpen => _evolutionPickerOpen;

		public int PlayerOneReviveCost => Mathf.Max(0, Plugin.PlayerOneReviveMutagenCost.Value);

		public float PlayerOneReviveHealthFraction => Mathf.Clamp(Plugin.PlayerOneReviveHealthFraction.Value, 0.01f, 1f);

		public int PlayerTwoReviveCost => Mathf.Max(0, Plugin.PlayerTwoReviveMutagenCost.Value);

		public float PlayerTwoReviveHealthFraction => Mathf.Clamp(Plugin.PlayerTwoReviveHealthFraction.Value, 0.01f, 1f);

		public int CurrentMutagenPoints
		{
			get
			{
				if (!((Object)(object)WorldStats.Instance != (Object)null))
				{
					return 0;
				}
				return WorldStats.Instance.CurrentNumMutagenPoints;
			}
		}

		public bool CanRevivePlayerOne
		{
			get
			{
				if (_playerOneAwaitingRevive && _evolutionPickerOpen && IsAlive(PlayerTwo))
				{
					return CurrentMutagenPoints >= PlayerOneReviveCost;
				}
				return false;
			}
		}

		public bool CanRevivePlayerTwo
		{
			get
			{
				if (_playerTwoAwaitingRevive && _evolutionPickerOpen && IsAlive(PlayerOne))
				{
					return CurrentMutagenPoints >= PlayerTwoReviveCost;
				}
				return false;
			}
		}

		public int PendingRevivePlayerNumber
		{
			get
			{
				if (!_playerOneAwaitingRevive)
				{
					if (!_playerTwoAwaitingRevive)
					{
						return 0;
					}
					return 2;
				}
				return 1;
			}
		}

		public int PendingReviveCost
		{
			get
			{
				if (PendingRevivePlayerNumber != 1)
				{
					return PlayerTwoReviveCost;
				}
				return PlayerOneReviveCost;
			}
		}

		public bool CanRevivePendingPlayer
		{
			get
			{
				if (PendingRevivePlayerNumber != 1)
				{
					return CanRevivePlayerTwo;
				}
				return CanRevivePlayerOne;
			}
		}

		public int PlayerOneCharmCount => GetCharmCount(PlayerOne);

		public int PlayerTwoCharmCount => GetCharmCount(PlayerTwo);

		public int SuppressedPlayerDeathDropCount => _suppressedPlayerDeathDropCount;

		public string PlayerTwoDamageHudStatus => _playerTwoDamageHudStatus;

		public string PlayerTwoAiHudStatus => _playerTwoAiHudStatus;

		public string CameraHudStatus => _cameraHudStatus;

		public float SharedCameraMidpointError { get; private set; } = float.PositiveInfinity;

		public float RenderCameraMidpointError { get; private set; } = float.PositiveInfinity;

		public bool IsFriendlyFireEnabled => Plugin.FriendlyFireEnabled.Value;

		public bool IsSharedNightVisionActive { get; private set; }

		public float SharedNightVisionCenterError { get; private set; } = float.PositiveInfinity;

		public float SharedNightVisionRadius { get; private set; } = -1f;

		public float SharedNightVisionRequiredRadius { get; private set; } = -1f;

		public float RenderSharedNightVisionCenterError { get; private set; } = float.PositiveInfinity;

		public float RenderSharedNightVisionRadius { get; private set; } = -1f;

		public float RenderSharedNightVisionMaxPlayerDistance { get; private set; } = -1f;

		public Vector2 RenderSharedNightVisionCenter { get; private set; } = new Vector2(float.NaN, float.NaN);

		public Vector2 RenderNightCameraPlayerOneViewport { get; private set; } = new Vector2(float.NaN, float.NaN);

		public Vector2 RenderNightCameraPlayerTwoViewport { get; private set; } = new Vector2(float.NaN, float.NaN);

		public string SharedNightVisionMaterialState { get; private set; } = "none";

		public LocalMultiplayerDriver(IntPtr ptr)
			: base(ptr)
		{
		}//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: 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_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0114: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0143: Unknown result type (might be due to invalid IL or missing references)


		public LocalMultiplayerDriver()
			: base(ClassInjector.DerivedConstructorPointer<LocalMultiplayerDriver>())
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this);
		}

		public void SetDebugInputOverride(int playerNumber, Vector2 move, Vector2 aim, bool dashHeld, bool primaryAttackHeld, int attackInputIndex = 0, bool interactHeld = false)
		{
			//IL_000c: 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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			switch (playerNumber)
			{
			case 1:
				_debugPlayerOneInputOverride = true;
				_debugPlayerOneMove = Vector2.ClampMagnitude(move, 1f);
				_debugPlayerOneAim = ((((Vector2)(ref aim)).sqrMagnitude > 0.001f) ? ((Vector2)(ref aim)).normalized : _playerOneAim);
				break;
			default:
				throw new ArgumentOutOfRangeException("playerNumber", playerNumber, "Debug input only supports player 1 or player 2.");
			case 2:
				_debugPlayerTwoInputOverride = true;
				_debugPlayerTwoMove = Vector2.ClampMagnitude(move, 1f);
				_debugPlayerTwoAim = ((((Vector2)(ref aim)).sqrMagnitude > 0.001f) ? ((Vector2)(ref aim)).normalized : Vector2.right);
				_debugPlayerTwoDashHeld = dashHeld;
				_debugPlayerTwoInteractHeld = interactHeld;
				Array.Clear(_debugPlayerTwoAttackHeld, 0, _debugPlayerTwoAttackHeld.Length);
				if (attackInputIndex < 0 || attackInputIndex >= _debugPlayerTwoAttackHeld.Length)
				{
					throw new ArgumentOutOfRangeException("attackInputIndex", attackInputIndex, "Debug attack input index must be between 0 and 4.");
				}
				_debugPlayerTwoAttackHeld[attackInputIndex] = primaryAttackHeld;
				break;
			}
		}

		public void SetDebugPlayerTwoGamepadIndexOverride(int gamepadIndex)
		{
			_debugPlayerTwoGamepadIndex = Math.Max(0, gamepadIndex);
		}

		public void SetDebugPlayerOneGamepadIndexOverride(int gamepadIndex)
		{
			_debugPlayerOneGamepadIndex = Math.Max(0, gamepadIndex);
		}

		public void ClearDebugPlayerOneGamepadIndexOverride()
		{
			_debugPlayerOneGamepadIndex = -1;
		}

		public void ClearDebugPlayerTwoGamepadIndexOverride()
		{
			_debugPlayerTwoGamepadIndex = -1;
		}

		public void ClearDebugInputOverride(int playerNumber = 0)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if (playerNumber == 0 || playerNumber == 1)
			{
				_debugPlayerOneInputOverride = false;
				_debugPlayerOneMove = Vector2.zero;
				_debugPlayerOneAim = Vector2.right;
			}
			if (playerNumber == 0 || playerNumber == 2)
			{
				_debugPlayerTwoInputOverride = false;
				_debugPlayerTwoMove = Vector2.zero;
				_debugPlayerTwoAim = Vector2.right;
				_debugPlayerTwoDashHeld = false;
				_debugPlayerTwoInteractHeld = false;
				Array.Clear(_debugPlayerTwoAttackHeld, 0, _debugPlayerTwoAttackHeld.Length);
			}
		}

		public bool TryApplyDebugMovement(CharacterMovement movement)
		{
			//IL_0039: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)movement == (Object)null)
			{
				return false;
			}
			PlayerCharacter componentInParent = ((Component)movement).GetComponentInParent<PlayerCharacter>();
			if (_debugPlayerOneInputOverride && IsSamePlayer(componentInParent, PlayerOne))
			{
				movement.SetMovement(IsPlayerOneDead ? Vector2.zero : _debugPlayerOneMove);
				return true;
			}
			if (_debugPlayerTwoInputOverride && IsSamePlayer(componentInParent, PlayerTwo))
			{
				movement.SetMovement(IsPlayerTwoDead ? Vector2.zero : _debugPlayerTwoMove);
				return true;
			}
			return false;
		}

		public void ApplyDebugDamage(int playerNumber, bool lethal, string source)
		{
			switch (playerNumber)
			{
			case 1:
				ApplyManualDamage(PlayerOne, PlayerTwo, source, "P1", lethal);
				break;
			case 2:
				ApplyManualDamage(PlayerTwo, PlayerOne, source, "P2", lethal);
				break;
			default:
				throw new ArgumentOutOfRangeException("playerNumber", playerNumber, "Debug damage only supports player 1 or player 2.");
			}
		}

		public void DebugRespawnPlayerTwo(string source)
		{
			ForceRespawnPlayerTwo(source);
		}

		public bool DebugRevivePlayerTwo(string source, out string result)
		{
			return TryRevivePlayerTwo(source, requireEvolutionPicker: false, out result);
		}

		public bool DebugRevivePlayerOne(string source, out string result)
		{
			return TryRevivePlayerOne(source, requireEvolutionPicker: false, out result);
		}

		public void SetEvolutionPickerOpen(bool isOpen)
		{
			_evolutionPickerOpen = isOpen;
		}

		public bool TrySpendMutagenToRevivePlayerTwo(out string result)
		{
			return TryRevivePlayerTwo("level-up UI", requireEvolutionPicker: true, out result);
		}

		public bool TrySpendMutagenToRevivePlayerOne(out string result)
		{
			return TryRevivePlayerOne("level-up UI", requireEvolutionPicker: true, out result);
		}

		public bool TrySpendMutagenToRevivePendingPlayer(out string result)
		{
			return PendingRevivePlayerNumber switch
			{
				1 => TrySpendMutagenToRevivePlayerOne(out result), 
				2 => TrySpendMutagenToRevivePlayerTwo(out result), 
				_ => FailNoPendingRevive(out result), 
			};
		}

		private static bool FailNoPendingRevive(out string result)
		{
			result = "Neither player is awaiting revival.";
			return false;
		}

		public void DebugDumpState(string source)
		{
			DumpState(source);
		}

		public void Awake()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			Scene activeScene = SceneManager.GetActiveScene();
			_sceneHandle = ((Scene)(ref activeScene)).handle;
			_beginCameraRenderingHandler = DelegateSupport.ConvertDelegate<Action<ScriptableRenderContext, Camera>>((Delegate)new Action<ScriptableRenderContext, Camera>(OnBeginCameraRendering));
			RenderPipelineManager.beginCameraRendering += _beginCameraRenderingHandler;
		}

		public void OnDestroy()
		{
			if ((Delegate)(object)_beginCameraRenderingHandler != (Delegate)null)
			{
				RenderPipelineManager.beginCameraRendering -= _beginCameraRenderingHandler;
				_beginCameraRenderingHandler = null;
			}
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		private static void OnBeginCameraRendering(ScriptableRenderContext context, Camera camera)
		{
			Instance?.UpdateSharedCameraFromCamera(camera, renderStage: true);
			Instance?.UpdateSharedNightVision(renderStage: true);
		}

		public void Update()
		{
			if (!Plugin.ModEnabled.Value)
			{
				CleanupPlayerTwoIfPresent();
				return;
			}
			ResetForSceneChanges();
			ValidateTrackedPlayers();
			LogConnectedGamepadsIfChanged();
			RefreshInput();
			HandleManualControls();
			TrySpawnPlayerTwo();
			RefreshDeathStateFromHealth();
			EnsurePlayerTwoDamageable();
			RefreshPlayerTwoAiTargetingIfDue();
			RefreshPlayerTwoSizeVisuals(force: false);
			MaintainPlayerSingleton();
		}

		public void LateUpdate()
		{
			if (Plugin.ModEnabled.Value)
			{
				MaintainPlayerSingleton();
				UpdateLocalPlayerAims();
				EnsureSharedCameraEnforcer(Camera.main);
				UpdateSharedNightVision(renderStage: false);
			}
		}

		public bool IsPlayerTwoComponent(Component component)
		{
			if (!Plugin.ModEnabled.Value || (Object)(object)component == (Object)null)
			{
				return false;
			}
			return IsPlayerTwo(ResolveLocalPlayerOwner(component));
		}

		public bool IsPlayerOneComponent(Component component)
		{
			if (!Plugin.ModEnabled.Value || (Object)(object)component == (Object)null)
			{
				return false;
			}
			return IsPlayerOne(ResolveLocalPlayerOwner(component));
		}

		public bool IsPlayerOneEvolutionHandler(EvolutionHandler handler)
		{
			if (!Plugin.ModEnabled.Value || (Object)(object)handler == (Object)null || _playerOneId == 0)
			{
				return false;
			}
			PlayerCharacter componentInParent = ((Component)handler).GetComponentInParent<PlayerCharacter>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				return ((Object)componentInParent).GetInstanceID() == _playerOneId;
			}
			return false;
		}

		public bool IsPlayerTwoEvolutionHandler(EvolutionHandler handler)
		{
			if (!Plugin.ModEnabled.Value || (Object)(object)handler == (Object)null || _playerTwoId == 0)
			{
				return false;
			}
			PlayerCharacter componentInParent = ((Component)handler).GetComponentInParent<PlayerCharacter>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				return ((Object)componentInParent).GetInstanceID() == _playerTwoId;
			}
			return false;
		}

		public EvolutionHandler GetPlayerOneEvolutionHandler()
		{
			if (!((Object)(object)PlayerOne != (Object)null))
			{
				return null;
			}
			return PlayerOne.PlayerEvolutionHandler;
		}

		public EvolutionHandler GetPlayerTwoEvolutionHandler()
		{
			if (!((Object)(object)PlayerTwo != (Object)null))
			{
				return null;
			}
			return PlayerTwo.PlayerEvolutionHandler;
		}

		public void RefreshPlayerTwoAttackLoadout()
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			if ((Object)(object)PlayerTwo == (Object)null)
			{
				return;
			}
			try
			{
				RepairPlayerTwoAttackState(PlayerTwo, resetCooldowns: false);
				RepairPlayerTwoDashState(PlayerTwo);
				RefreshPlayerTwoSizeVisuals(force: true);
			}
			catch (Exception ex)
			{
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(75, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Failed to refresh the player-two attack loadout after an evolution change: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				logger.LogWarning(val);
			}
		}

		public void ApplyPlayerTwoMovement(CharacterMovement movement)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (IsPlayerTwoDead)
			{
				movement.SetMovement(Vector2.zero);
			}
			else
			{
				movement.SetMovement(InputState.Move);
			}
		}

		public void ApplyPlayerOneMovement(CharacterMovement movement)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			movement.SetMovement(IsPlayerOneDead ? Vector2.zero : _playerOneMove);
		}

		public void HandlePlayerTwoDash(PlayerDashManager dashManager)
		{
			if (!IsPlayerTwoDead)
			{
				if (InputState.DashPressed)
				{
					((CharacterDashManager)dashManager).StartDash();
				}
				if (InputState.DashReleased)
				{
					((CharacterDashManager)dashManager).DashInputReleased();
				}
			}
		}

		public void HandlePlayerTwoAttack(AAttackHandler attackHandler)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if (IsPlayerTwoDead)
			{
				return;
			}
			int num = AttackSlotToInputIndex(attackHandler.AttackSlot);
			if (num >= 0)
			{
				if (InputState.AttackPressed[num])
				{
					ApplyPlayerTwoAttackAim(attackHandler);
					((CharacterHandleWeapon)attackHandler).ShootStart();
				}
				if (InputState.AttackReleased[num])
				{
					ApplyPlayerTwoAttackAim(attackHandler);
					((CharacterHandleWeapon)attackHandler).ShootStop();
				}
			}
		}

		public void HandlePlayerTwoInteraction(PlayerInteraction interaction)
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			if (IsPlayerTwoDead || (Object)(object)PlayerTwo == (Object)null || !InputState.InteractPressed)
			{
				return;
			}
			IPlayerInteractable val = ((interaction != null) ? interaction.CurrentInteractable : null);
			Burrow currentBurrow = PlayerTwo.CurrentBurrow;
			if (val == null && (Object)(object)currentBurrow != (Object)null)
			{
				val = ((Il2CppObjectBase)currentBurrow).Cast<IPlayerInteractable>();
			}
			if (val == null)
			{
				return;
			}
			Burrow val2 = ((Il2CppObjectBase)val).TryCast<Burrow>();
			if (!val.CanInteract && (!((Object)(object)val2 != (Object)null) || !PlayerTwo.IsInBurrow))
			{
				return;
			}
			PlayerCharacter instance = PlayerCharacter.Instance;
			try
			{
				PlayerCharacter.Instance = PlayerTwo;
				val.InteractWithPlayer();
			}
			catch (Exception ex)
			{
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(51, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Player two could not use the focused interactable: ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex.Message);
				}
				logger.LogWarning(val3);
			}
			finally
			{
				PlayerCharacter.Instance = instance;
			}
		}

		public bool BeginMushroomConsumerUpdate(EdibleItemConsumer consumer)
		{
			PlayerCharacter val = ((consumer != null) ? ((Component)consumer).GetComponentInParent<PlayerCharacter>() : null);
			if (!IsPlayerOne(val) && !IsPlayerTwo(val))
			{
				return false;
			}
			if (_mushroomConsumerSingletonDepth == 0)
			{
				_mushroomConsumerPreviousSingleton = PlayerCharacter.Instance;
			}
			_mushroomConsumerSingletonDepth++;
			PlayerCharacter.Instance = val;
			return true;
		}

		public void EndMushroomConsumerUpdate()
		{
			if (_mushroomConsumerSingletonDepth > 0)
			{
				_mushroomConsumerSingletonDepth--;
				if (_mushroomConsumerSingletonDepth == 0)
				{
					PlayerCharacter.Instance = _mushroomConsumerPreviousSingleton;
					_mushroomConsumerPreviousSingleton = null;
				}
			}
		}

		public bool BeginMushroomEffectCapture(MushroomManager manager)
		{
			PlayerCharacter instance = PlayerCharacter.Instance;
			if ((Object)(object)manager == (Object)null || (!IsPlayerOne(instance) && !IsPlayerTwo(instance)))
			{
				return false;
			}
			EnsureMushroomEffectLists(manager);
			if (_mushroomConsumptionRoutingDepth == 0)
			{
				_mushroomEffectsBeforeConsumption = manager._activeEffects;
			}
			_mushroomConsumptionRoutingDepth++;
			manager._activeEffects = (IsPlayerTwo(instance) ? _playerTwoMushroomEffects : _playerOneMushroomEffects);
			return true;
		}

		public void EndMushroomEffectCapture(MushroomManager manager)
		{
			if (!((Object)(object)manager == (Object)null) && _mushroomConsumptionRoutingDepth > 0)
			{
				_mushroomConsumptionRoutingDepth--;
				if (_mushroomConsumptionRoutingDepth == 0)
				{
					manager._activeEffects = _mushroomEffectsBeforeConsumption ?? _playerOneMushroomEffects;
					_mushroomEffectsBeforeConsumption = null;
				}
			}
		}

		public bool TryUpdateOwnedMushroomEffects(MushroomManager manager)
		{
			if (_updatingOwnedMushroomEffects || (Object)(object)manager == (Object)null || !Plugin.ModEnabled.Value)
			{
				return false;
			}
			if (_playerOneMushroomEffects == null && ((Object)(object)PlayerOne == (Object)null || (Object)(object)PlayerTwo == (Object)null))
			{
				return false;
			}
			EnsureMushroomEffectLists(manager);
			List<MushroomImpactStateInfo> activeEffects = manager._activeEffects;
			PlayerCharacter instance = PlayerCharacter.Instance;
			_updatingOwnedMushroomEffects = true;
			try
			{
				UpdateOwnedMushroomEffects(manager, PlayerOne, _playerOneMushroomEffects, 1);
				UpdateOwnedMushroomEffects(manager, PlayerTwo, _playerTwoMushroomEffects, 2);
			}
			finally
			{
				manager._activeEffects = activeEffects ?? _playerOneMushroomEffects;
				PlayerCharacter.Instance = instance;
				_updatingOwnedMushroomEffects = false;
			}
			return true;
		}

		public bool DebugQueueMushroomEffectForPlayer(int playerNumber, EMushroomEffect effect, out string result)
		{
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			MushroomManager instance = AMonoBehaviourSingleton<MushroomManager>.Instance;
			PlayerCharacter val = (PlayerCharacter)(playerNumber switch
			{
				2 => PlayerTwo, 
				1 => PlayerOne, 
				_ => null, 
			});
			if ((Object)(object)instance == (Object)null || !IsAlive(val))
			{
				result = $"manager={(Object)(object)instance != (Object)null}, P{playerNumber}Alive={IsAlive(val)}.";
				return false;
			}
			EnsureMushroomEffectLists(instance);
			int playerOneMushroomEffectCount = PlayerOneMushroomEffectCount;
			int playerTwoMushroomEffectCount = PlayerTwoMushroomEffectCount;
			PlayerCharacter instance2 = PlayerCharacter.Instance;
			bool flag = false;
			_lastMushroomEffectUpdatePlayerNumber = 0;
			try
			{
				PlayerCharacter.Instance = val;
				flag = BeginMushroomEffectCapture(instance);
				instance.TriggerMushroomEffect(effect, 0f);
			}
			finally
			{
				if (flag)
				{
					EndMushroomEffectCapture(instance);
				}
				PlayerCharacter.Instance = instance2;
			}
			bool flag2 = ((playerNumber != 1) ? (PlayerTwoMushroomEffectCount > playerTwoMushroomEffectCount && PlayerOneMushroomEffectCount == playerOneMushroomEffectCount) : (PlayerOneMushroomEffectCount > playerOneMushroomEffectCount && PlayerTwoMushroomEffectCount == playerTwoMushroomEffectCount));
			result = $"effect={effect}, routed={flag}, P1 effects {playerOneMushroomEffectCount}->{PlayerOneMushroomEffectCount}, P2 effects {playerTwoMushroomEffectCount}->{PlayerTwoMushroomEffectCount}.";
			return flag && flag2;
		}

		public void DebugClearMushroomEffects()
		{
			_playerOneMushroomEffects?.Clear();
			_playerTwoMushroomEffects?.Clear();
			_lastMushroomEffectUpdatePlayerNumber = 0;
		}

		private void EnsureMushroomEffectLists(MushroomManager manager)
		{
			int instanceID = ((Object)manager).GetInstanceID();
			if (_mushroomManagerId != instanceID || _playerOneMushroomEffects == null || _playerTwoMushroomEffects == null)
			{
				_mushroomManagerId = instanceID;
				_playerOneMushroomEffects = manager._activeEffects ?? new List<MushroomImpactStateInfo>();
				_playerTwoMushroomEffects = new List<MushroomImpactStateInfo>();
				_mushroomEffectsBeforeConsumption = null;
				_mushroomConsumptionRoutingDepth = 0;
				_lastMushroomEffectUpdatePlayerNumber = 0;
			}
			else
			{
				List<MushroomImpactStateInfo> activeEffects = manager._activeEffects;
				if (!_updatingOwnedMushroomEffects && _mushroomConsumptionRoutingDepth == 0 && activeEffects != null && ((Il2CppObjectBase)activeEffects).Pointer != ((Il2CppObjectBase)_playerOneMushroomEffects).Pointer && ((Il2CppObjectBase)activeEffects).Pointer != ((Il2CppObjectBase)_playerTwoMushroomEffects).Pointer)
				{
					_playerOneMushroomEffects = activeEffects;
					_playerTwoMushroomEffects = new List<MushroomImpactStateInfo>();
				}
			}
		}

		private void UpdateOwnedMushroomEffects(MushroomManager manager, PlayerCharacter owner, List<MushroomImpactStateInfo> effects, int playerNumber)
		{
			if (effects != null && effects.Count != 0)
			{
				if (!IsAlive(owner))
				{
					effects.Clear();
					return;
				}
				manager._activeEffects = effects;
				PlayerCharacter.Instance = owner;
				_lastMushroomEffectUpdatePlayerNumber = playerNumber;
				manager.UpdateMushroomEffectLogics();
			}
		}

		public void DebugRefreshPlayerTwoSize()
		{
			RefreshPlayerTwoSizeVisuals(force: true);
		}

		public bool IsPlayerTwoGamepadContext(CallbackContext context)
		{
			if (!Plugin.ModEnabled.Value)
			{
				return false;
			}
			ReadOnlyArray<Gamepad> all = Gamepad.all;
			int playerTwoGamepadIndex = GetPlayerTwoGamepadIndex();
			if (all.Count <= playerTwoGamepadIndex)
			{
				return false;
			}
			InputControl control = context.control;
			InputDevice val = ((control != null) ? control.device : null);
			if (val == null)
			{
				return false;
			}
			return val.deviceId == ((InputDevice)all[playerTwoGamepadIndex]).deviceId;
		}

		public void RecordFilteredStockInput(CallbackContext context)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			if (Plugin.DiagnosticsEnabled.Value && !_loggedFilteredStockInput)
			{
				InputControl control = context.control;
				InputDevice val = ((control != null) ? control.device : null);
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(83, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Filtered stock player-one input from player-two device: action=");
					InputAction action = context.action;
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(((action != null) ? action.name : null) ?? "unknown");
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", control=");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(((control != null) ? control.path : null) ?? "unknown");
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", device=");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(((val != null) ? ((InputControl)val).displayName : null) ?? ((val != null) ? ((InputControl)val).name : null) ?? "unknown");
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(".");
				}
				logger.LogInfo(val2);
				_loggedFilteredStockInput = true;
			}
		}

		public bool ShouldSuppressStockAimInjector(PlayerAttackAimInjector injector)
		{
			if (!TryGetLocalPlayerAim((Component)(object)injector, out var _, out var _))
			{
				return false;
			}
			return true;
		}

		public bool TryApplyLocalPlayerAim(WeaponAim2D weaponAim)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (!TryGetLocalPlayerAim((Component)(object)weaponAim, out var player, out var aim))
			{
				return false;
			}
			if (IsLocalPlayerDead(player))
			{
				return true;
			}
			ConfigureWeaponAim((WeaponAim)(object)weaponAim, aim, applyRotation: false);
			return true;
		}

		public bool TryApplyLocalPlayerAttackDirection(EICCharacterAttack attack)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (!TryGetLocalPlayerAim((Component)(object)attack, out var player, out var aim))
			{
				return false;
			}
			if (IsLocalPlayerDead(player))
			{
				return true;
			}
			ConfigureWeaponAim(attack.WeaponAim, aim, applyRotation: true);
			attack._AimDirectionAtStartOfAttack_k__BackingField = aim;
			return true;
		}

		public bool TryUpdateLocalPlayerAimIndicator(GamepadAimDirection indicator)
		{
			//IL_0051: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			if (!TryGetLocalPlayerAim((Component)(object)indicator, out var player, out var aim))
			{
				return false;
			}
			if (IsLocalPlayerDead(player) || (Object)(object)((Component)indicator).gameObject == (Object)null)
			{
				return true;
			}
			if (!((Component)indicator).gameObject.activeSelf)
			{
				((Component)indicator).gameObject.SetActive(true);
			}
			if (!((Behaviour)indicator).enabled)
			{
				((Behaviour)indicator).enabled = true;
			}
			indicator.SetCurrentAim(new Vector2(aim.x, aim.y));
			return true;
		}

		public void UpdateSharedCamera(CombatCamera combatCamera)
		{
			Camera camera = (((Object)(object)combatCamera != (Object)null && (Object)(object)combatCamera.Camera != (Object)null) ? combatCamera.Camera : Camera.main);
			EnsureSharedCameraEnforcer(camera);
			UpdateSharedCameraFromCamera(camera, renderStage: false);
		}

		public void UpdateSharedCameraFromCamera(Camera camera, bool renderStage)
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: 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_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)camera == (Object)null)
			{
				return;
			}
			bool flag = IsAliveForCamera(PlayerOne);
			bool flag2 = IsAliveForCamera(PlayerTwo);
			if (!flag && !flag2)
			{
				_cameraHudStatus = "CAM: NONE";
				return;
			}
			_cameraHudStatus = ((flag && flag2) ? "CAM: BOTH" : (flag2 ? "CAM: P2" : "CAM: P1"));
			Transform transform = ((Component)camera).transform;
			Vector3 val = ((flag && flag2) ? ((((Component)PlayerOne).transform.position + ((Component)PlayerTwo).transform.position) * 0.5f) : (flag2 ? ((Component)PlayerTwo).transform.position : ((Component)PlayerOne).transform.position));
			Vector3 position = transform.position;
			int instanceID = ((Object)camera).GetInstanceID();
			if (!_hasSharedCameraState || _cameraId != instanceID)
			{
				_cameraId = instanceID;
				_baseOrthographicSize = (camera.orthographic ? camera.orthographicSize : 0f);
				_smoothedOrthographicSize = camera.orthographicSize;
				_smoothedCameraCenter = new Vector2(position.x, position.y);
				_hasSharedCameraState = true;
			}
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(val.x, val.y);
			if (renderStage)
			{
				_smoothedCameraCenter = val2;
			}
			else
			{
				float num = 1f - Mathf.Exp((0f - Time.unscaledDeltaTime) * Mathf.Max(0.1f, Plugin.CameraFollowLerpSpeed.Value));
				_smoothedCameraCenter = Vector2.Lerp(_smoothedCameraCenter, val2, num);
			}
			transform.position = new Vector3(_smoothedCameraCenter.x, _smoothedCameraCenter.y, position.z);
			SharedCameraMidpointError = Vector2.Distance(new Vector2(transform.position.x, transform.position.y), val2);
			if (renderStage)
			{
				RenderCameraMidpointError = SharedCameraMidpointError;
			}
			if (camera.orthographic)
			{
				float num2 = ((flag && flag2) ? Vector2.Distance(Vector2.op_Implicit(((Component)PlayerOne).transform.position), Vector2.op_Implicit(((Component)PlayerTwo).transform.position)) : 0f);
				float num3 = Mathf.Clamp(Mathf.Max(_baseOrthographicSize, num2 * Mathf.Max(0f, Plugin.CameraDistanceZoomMultiplier.Value) + Mathf.Max(0f, Plugin.CameraZoomPadding.Value)), _baseOrthographicSize, _baseOrthographicSize * Mathf.Max(1f, Plugin.CameraMaxZoomMultiplier.Value));
				float num4 = 1f - Mathf.Exp((0f - Time.unscaledDeltaTime) * Mathf.Max(0.1f, Plugin.CameraZoomLerpSpeed.Value));
				_smoothedOrthographicSize = Mathf.Lerp(_smoothedOrthographicSize, num3, num4);
				camera.orthographicSize = _smoothedOrthographicSize;
			}
		}

		private void EnsureSharedCameraEnforcer(Camera camera)
		{
			if ((Object)(object)camera == (Object)null || (Object)(object)((Component)camera).gameObject == (Object)null)
			{
				return;
			}
			int instanceID = ((Object)camera).GetInstanceID();
			if (_cameraEnforcerId != instanceID || !((Object)(object)((Component)camera).GetComponent<SharedCameraEnforcer>() != (Object)null))
			{
				if ((Object)(object)((Component)camera).GetComponent<SharedCameraEnforcer>() == (Object)null)
				{
					((Component)camera).gameObject.AddComponent<SharedCameraEnforcer>();
				}
				_cameraEnforcerId = instanceID;
			}
		}

		private void UpdateSharedNightVision(bool renderStage)
		{
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: 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_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: 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_0258: 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_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: 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_028a: Unknown result type (might be due to invalid IL or missing references)
			DayAndNightCycleManager instance = AMonoBehaviourSingleton<DayAndNightCycleManager>.Instance;
			if (!Plugin.SharedNightVisionEnabled.Value || (Object)(object)instance == (Object)null)
			{
				RestoreSharedNightVisionRadius();
				return;
			}
			Camera val = (((Object)(object)Camera.main != (Object)null) ? Camera.main : instance._nightEyesCamera);
			Material nightShaderMaterialToEdit = instance._nightShaderMaterialToEdit;
			if ((Object)(object)nightShaderMaterialToEdit == (Object)null || (Object)(object)val == (Object)null)
			{
				ClearSharedNightVisionTracking();
				return;
			}
			NightVisionMaterialState orRefreshNightVisionMaterialState = GetOrRefreshNightVisionMaterialState(nightShaderMaterialToEdit);
			bool flag = IsAliveForCamera(PlayerOne);
			bool flag2 = IsAliveForCamera(PlayerTwo);
			if (!flag && !flag2)
			{
				RestoreSharedNightVisionRadius();
				return;
			}
			Vector3 val2 = (flag ? val.WorldToViewportPoint(((Component)PlayerOne).transform.position) : val.WorldToViewportPoint(((Component)PlayerTwo).transform.position));
			Vector3 val3 = (flag2 ? val.WorldToViewportPoint(((Component)PlayerTwo).transform.position) : val2);
			Vector3 val4 = ((flag && flag2) ? ((val2 + val3) * 0.5f) : (flag2 ? val3 : val2));
			float num = (val3.x - val2.x) * Mathf.Max(1f, val.aspect);
			float num2 = val3.y - val2.y;
			float num3 = ((flag && flag2) ? (Mathf.Sqrt(num * num + num2 * num2) * 0.5f) : 0f);
			float num4 = ((flag && flag2) ? Mathf.Max(0f, Plugin.SharedNightVisionPadding.Value) : 0f);
			float num5 = Mathf.Max(0f, orRefreshNightVisionMaterialState.BaseViewportRadius + num3 + num4);
			float gradientRadius = Mathf.Max(0f, orRefreshNightVisionMaterialState.BaseGradientRadius + num3 + num4);
			ApplySharedNightVisionToMaterial(nightShaderMaterialToEdit, val4, num5, gradientRadius);
			ApplySharedNightVisionToRendererMaterials(instance, val4, num5, gradientRadius);
			SharedNightVisionRadius = num5;
			SharedNightVisionRequiredRadius = num5;
			Vector4 vector = nightShaderMaterialToEdit.GetVector(DayAndNightCycleManager.VIEWPORT_CENTER_SHADER_PARAM_HASH);
			SharedNightVisionCenterError = Vector2.Distance(new Vector2(vector.x, vector.y), new Vector2(val4.x, val4.y));
			IsSharedNightVisionActive = flag && flag2;
			if (renderStage)
			{
				RenderSharedNightVisionCenterError = SharedNightVisionCenterError;
				RenderSharedNightVisionRadius = num5;
				RenderSharedNightVisionMaxPlayerDistance = num3;
				RenderSharedNightVisionCenter = new Vector2(val4.x, val4.y);
				RenderNightCameraPlayerOneViewport = new Vector2(val2.x, val2.y);
				RenderNightCameraPlayerTwoViewport = new Vector2(val3.x, val3.y);
				SharedNightVisionMaterialState = DescribeNightVisionMaterials(instance);
			}
		}

		private NightVisionMaterialState GetOrRefreshNightVisionMaterialState(Material material)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: 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_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)
			int instanceID = ((Object)material).GetInstanceID();
			if (!_nightVisionMaterialStates.TryGetValue(instanceID, out var value) || (Object)(object)value.Material == (Object)null)
			{
				value = new NightVisionMaterialState
				{
					Material = material,
					BaseCenter = material.GetVector(DayAndNightCycleManager.VIEWPORT_CENTER_SHADER_PARAM_HASH),
					BaseViewportRadius = material.GetFloat(DayAndNightCycleManager.VIEWPORT_RADIUS_SHADER_PARAM_HASH),
					BaseGradientRadius = material.GetFloat(DayAndNightCycleManager.GRADIENT_RADIUS_SHADER_PARAM_HASH)
				};
				_nightVisionMaterialStates[instanceID] = value;
			}
			Vector4 vector = material.GetVector(DayAndNightCycleManager.VIEWPORT_CENTER_SHADER_PARAM_HASH);
			float num = material.GetFloat(DayAndNightCycleManager.VIEWPORT_RADIUS_SHADER_PARAM_HASH);
			float num2 = material.GetFloat(DayAndNightCycleManager.GRADIENT_RADIUS_SHADER_PARAM_HASH);
			if (float.IsNaN(value.LastAppliedCenter.x) || Vector4.Distance(vector, value.LastAppliedCenter) > 0.0001f)
			{
				value.BaseCenter = vector;
			}
			if (float.IsNaN(value.LastAppliedViewportRadius) || !Mathf.Approximately(num, value.LastAppliedViewportRadius))
			{
				value.BaseViewportRadius = num;
			}
			if (float.IsNaN(value.LastAppliedGradientRadius) || !Mathf.Approximately(num2, value.LastAppliedGradientRadius))
			{
				value.BaseGradientRadius = num2;
			}
			return value;
		}

		private void ApplySharedNightVisionToMaterial(Material material, Vector3 center, float viewportRadius, float gradientRadius)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)material == (Object)null) && material.HasProperty(DayAndNightCycleManager.VIEWPORT_CENTER_SHADER_PARAM_HASH) && material.HasProperty(DayAndNightCycleManager.VIEWPORT_RADIUS_SHADER_PARAM_HASH) && material.HasProperty(DayAndNightCycleManager.GRADIENT_RADIUS_SHADER_PARAM_HASH))
			{
				NightVisionMaterialState orRefreshNightVisionMaterialState = GetOrRefreshNightVisionMaterialState(material);
				material.SetVector(DayAndNightCycleManager.VIEWPORT_CENTER_SHADER_PARAM_HASH, new Vector4(center.x, center.y, 0f, 0f));
				material.SetFloat(DayAndNightCycleManager.VIEWPORT_RADIUS_SHADER_PARAM_HASH, viewportRadius);
				material.SetFloat(DayAndNightCycleManager.GRADIENT_RADIUS_SHADER_PARAM_HASH, gradientRadius);
				orRefreshNightVisionMaterialState.LastAppliedCenter = new Vector4(center.x, center.y, 0f, 0f);
				orRefreshNightVisionMaterialState.LastAppliedViewportRadius = viewportRadius;
				orRefreshNightVisionMaterialState.LastAppliedGradientRadius = gradientRadius;
			}
		}

		private void ApplySharedNightVisionToRendererMaterials(DayAndNightCycleManager manager, Vector3 center, float viewportRadius, float gradientRadius)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				object obj;
				if (manager == null)
				{
					obj = null;
				}
				else
				{
					UniversalRendererData universalRendererData = manager._universalRendererData;
					obj = ((universalRendererData != null) ? ((ScriptableRendererData)universalRendererData).rendererFeatures : null);
				}
				List<ScriptableRendererFeature> val = (List<ScriptableRendererFeature>)obj;
				if (val != null)
				{
					for (int i = 0; i < val.Count; i++)
					{
						ScriptableRendererFeature obj2 = val[i];
						FullScreenPassRendererFeature val2 = ((obj2 != null) ? ((Il2CppObjectBase)obj2).TryCast<FullScreenPassRendererFeature>() : null);
						ApplySharedNightVisionToMaterial((val2 != null) ? val2.passMaterial : null, center, viewportRadius, gradientRadius);
					}
				}
			}
			catch (Exception ex)
			{
				if (Plugin.DiagnosticsEnabled.Value)
				{
					ManualLogSource logger = Plugin.Logger;
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(47, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Unable to update all night renderer materials: ");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex.Message);
					}
					logger.LogWarning(val3);
				}
			}
		}

		private string DescribeNightVisionMaterials(DayAndNightCycleManager manager)
		{
			List<string> list = new List<string>();
			AddNightVisionMaterialDescription(list, "manager", (manager != null) ? manager._nightShaderMaterialToEdit : null);
			try
			{
				object obj;
				if (manager == null)
				{
					obj = null;
				}
				else
				{
					UniversalRendererData universalRendererData = manager._universalRendererData;
					obj = ((universalRendererData != null) ? ((ScriptableRendererData)universalRendererData).rendererFeatures : null);
				}
				List<ScriptableRendererFeature> val = (List<ScriptableRendererFeature>)obj;
				if (val != null)
				{
					for (int i = 0; i < val.Count; i++)
					{
						ScriptableRendererFeature obj2 = val[i];
						FullScreenPassRendererFeature val2 = ((obj2 != null) ? ((Il2CppObjectBase)obj2).TryCast<FullScreenPassRendererFeature>() : null);
						if ((Object)(object)((val2 != null) ? val2.passMaterial : null) != (Object)null && val2.passMaterial.HasProperty(DayAndNightCycleManager.VIEWPORT_CENTER_SHADER_PARAM_HASH))
						{
							AddNightVisionMaterialDescription(list, $"feature[{i}]", val2.passMaterial);
						}
					}
				}
			}
			catch (Exception ex)
			{
				list.Add("renderer-error=" + ex.Message);
			}
			if (list.Count <= 0)
			{
				return "none";
			}
			return string.Join("; ", list);
		}

		private static void AddNightVisionMaterialDescription(List<string> descriptions, string source, Material material)
		{
			//IL_0021: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)material == (Object)null)
			{
				descriptions.Add(source + "=null");
				return;
			}
			Vector4 vector = material.GetVector(DayAndNightCycleManager.VIEWPORT_CENTER_SHADER_PARAM_HASH);
			float value = material.GetFloat(DayAndNightCycleManager.VIEWPORT_RADIUS_SHADER_PARAM_HASH);
			float value2 = material.GetFloat(DayAndNightCycleManager.GRADIENT_RADIUS_SHADER_PARAM_HASH);
			DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(30, 8);
			defaultInterpolatedStringHandler.AppendFormatted(source);
			defaultInterpolatedStringHandler.AppendLiteral("=");
			defaultInterpolatedStringHandler.AppendFormatted(((Object)material).name);
			defaultInterpolatedStringHandler.AppendLiteral("#");
			defaultInterpolatedStringHandler.AppendFormatted(((Object)material).GetInstanceID());
			defaultInterpolatedStringHandler.AppendLiteral(" shader=");
			Shader shader = material.shader;
			defaultInterpolatedStringHandler.AppendFormatted(((shader != null) ? ((Object)shader).name : null) ?? "null");
			defaultInterpolatedStringHandler.AppendLiteral(" center=(");
			defaultInterpolatedStringHandler.AppendFormatted(vector.x, "0.000");
			defaultInterpolatedStringHandler.AppendLiteral(",");
			defaultInterpolatedStringHandler.AppendFormatted(vector.y, "0.000");
			defaultInterpolatedStringHandler.AppendLiteral(") radius=");
			defaultInterpolatedStringHandler.AppendFormatted(value, "0.000");
			defaultInterpolatedStringHandler.AppendLiteral("/");
			defaultInterpolatedStringHandler.AppendFormatted(value2, "0.000");
			descriptions.Add(defaultInterpolatedStringHandler.ToStringAndClear());
		}

		private void RestoreSharedNightVisionRadius()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			float num = RestoreNightVisionMaterials();
			IsSharedNightVisionActive = false;
			SharedNightVisionCenterError = float.PositiveInfinity;
			SharedNightVisionRadius = num;
			SharedNightVisionRequiredRadius = num;
			RenderSharedNightVisionCenterError = float.PositiveInfinity;
			RenderSharedNightVisionRadius = num;
			RenderSharedNightVisionMaxPlayerDistance = -1f;
			RenderSharedNightVisionCenter = new Vector2(float.NaN, float.NaN);
			RenderNightCameraPlayerOneViewport = new Vector2(float.NaN, float.NaN);
			RenderNightCameraPlayerTwoViewport = new Vector2(float.NaN, float.NaN);
			SharedNightVisionMaterialState = "none";
		}

		private void ClearSharedNightVisionTracking()
		{
			//IL_0066: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			RestoreNightVisionMaterials();
			_nightVisionMaterialStates.Clear();
			IsSharedNightVisionActive = false;
			SharedNightVisionCenterError = float.PositiveInfinity;
			SharedNightVisionRadius = -1f;
			SharedNightVisionRequiredRadius = -1f;
			RenderSharedNightVisionCenterError = float.PositiveInfinity;
			RenderSharedNightVisionRadius = -1f;
			RenderSharedNightVisionMaxPlayerDistance = -1f;
			RenderSharedNightVisionCenter = new Vector2(float.NaN, float.NaN);
			RenderNightCameraPlayerOneViewport = new Vector2(float.NaN, float.NaN);
			RenderNightCameraPlayerTwoViewport = new Vector2(float.NaN, float.NaN);
			SharedNightVisionMaterialState = "none";
		}

		private float RestoreNightVisionMaterials()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			float num = -1f;
			foreach (NightVisionMaterialState value in _nightVisionMaterialStates.Values)
			{
				if (!((Object)(object)value.Material == (Object)null))
				{
					value.Material.SetVector(DayAndNightCycleManager.VIEWPORT_CENTER_SHADER_PARAM_HASH, value.BaseCenter);
					value.Material.SetFloat(DayAndNightCycleManager.VIEWPORT_RADIUS_SHADER_PARAM_HASH, value.BaseViewportRadius);
					value.Material.SetFloat(DayAndNightCycleManager.GRADIENT_RADIUS_SHADER_PARAM_HASH, value.BaseGradientRadius);
					value.LastAppliedCenter = new Vector4(float.NaN, float.NaN, float.NaN, float.NaN);
					value.LastAppliedViewportRadius = float.NaN;
					value.LastAppliedGradientRadius = float.NaN;
					if (num < 0f)
					{
						num = value.BaseViewportRadius;
					}
				}
			}
			return num;
		}

		public void RestorePlayerOneSingletonIfNeeded(PlayerCharacter candidate)
		{
			if (!((Object)(object)candidate == (Object)null) && _playerTwoId != 0 && _playerOneId != 0 && ((Object)candidate).GetInstanceID() == _playerTwoId && (Object)(object)PlayerOne != (Object)null && !IsPlayerOneDead)
			{
				PlayerCharacter.Instance = PlayerOne;
			}
		}

		public bool TryHandlePlayerDeath(PlayerCharacter player, Health health)
		{
			if (!Plugin.ModEnabled.Value || (Object)(object)player == (Object)null)
			{
				return false;
			}
			if (IsPlayerTwoComponent((Component)(object)player))
			{
				if (!Plugin.PreventPlayerTwoDeathRunEnd.Value || !Plugin.ContinueRunWhileAnyPlayerAlive.Value || !IsAlive(PlayerOne))
				{
					return false;
				}
				MarkPlayerDead(player, health, isPlayerTwo: true);
				if (Plugin.RemovePlayerTwoOnDeath.Value)
				{
					RemovePlayerTwoAfterDeath(player);
				}
				PlayerCharacter.Instance = PlayerOne;
				MaintainPlayerSingleton();
				_playerTwoDamageHudStatus = "P2 DMG: DEAD";
				_cameraHudStatus = "CAM: P1";
				Plugin.Logger.LogInfo((object)(Plugin.RemovePlayerTwoOnDeath.Value ? "Player two died; removed P2's world entity and opened the revive slot while P1 remains alive." : "Player two died; leaving P2 dead and suppressing the single-player run-end flow while P1 is alive."));
				return true;
			}
			if (!IsPlayerOne(player) || !Plugin.ContinueRunWhileAnyPlayerAlive.Value || !IsAlive(PlayerTwo))
			{
				return false;
			}
			CapturePlayerOneVisualState(player);
			_playerOneAwaitingRevive = true;
			MarkPlayerDead(player, health, isPlayerTwo: false);
			TransferEvolutionProgressToPlayerTwo();
			PlayerCharacter.Instance = PlayerTwo;
			if (Plugin.RemovePlayerOneOnDeath.Value)
			{
				RemovePlayerOneAfterDeath(player);
			}
			NotifyNearbyAiAboutPlayer(PlayerTwo, "player one death fallback", logSummary: true);
			MaintainPlayerSingleton();
			_cameraHudStatus = "CAM: P2";
			Plugin.Logger.LogInfo((object)(Plugin.RemovePlayerOneOnDeath.Value ? "Player one died while P2 is alive; removed P1's world entity and handed camera, XP, and level-up ownership to P2." : "Player one died while P2 is alive; suppressing the single-player run-end flow and shifting control/camera singleton to P2."));
			return true;
		}

		public bool ShouldSuppressLocalPlayerFoodDrop(DropItemsOnDeath dropItemsOnDeath)
		{
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Expected O, but got Unknown
			if (!Plugin.ModEnabled.Value || !Plugin.SuppressPlayerFoodDrops.Value || (Object)(object)dropItemsOnDeath == (Object)null)
			{
				return false;
			}
			PlayerCharacter componentInParent = ((Component)dropItemsOnDeath).GetComponentInParent<PlayerCharacter>();
			bool flag = (Object)(object)componentInParent != (Object)null && (Object)(object)((Component)componentInParent).gameObject != (Object)null && ((Object)((Component)componentInParent).gameObject).name.StartsWith("LocalMultiplayer_Player2", StringComparison.Ordinal);
			bool flag2 = (Object)(object)componentInParent != (Object)null && (Object)(object)((Component)componentInParent).gameObject != (Object)null && ((Object)((Component)componentInParent).gameObject).name.StartsWith("LocalMultiplayer_Player1_PendingDestroy", StringComparison.Ordinal);
			if (!IsPlayerOne(componentInParent) && !IsPlayerTwoComponent((Component)(object)componentInParent) && !flag && !flag2)
			{
				return false;
			}
			_suppressedPlayerDeathDropCount++;
			if (Plugin.DiagnosticsEnabled.Value)
			{
				ManualLogSource logger = Plugin.Logger;
				bool flag3 = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(68, 2, ref flag3);
				if (flag3)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Suppressed player death food drop for ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)componentInParent).name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; total suppressed callbacks=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_suppressedPlayerDeathDropCount);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				logger.LogInfo(val);
			}
			return true;
		}

		public bool ShouldForcePlayerTwoDamageable(Health health)
		{
			if (!Plugin.ModEnabled.Value || !Plugin.ForcePlayerTwoDamageEnabled.Value || (Object)(object)health == (Object)null || IsPlayerTwoDead)
			{
				return false;
			}
			if (!IsPlayerTwoComponent((Component)(object)health))
			{
				return false;
			}
			ClearDamageLocks(health);
			return true;
		}

		public bool TryForcePlayerTwoDamageOutput(Health health, float requestedDamage, float computedDamage, out float forcedDamage)
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			forcedDamage = computedDamage;
			if (!Plugin.ModEnabled.Value || !Plugin.ForcePlayerTwoDamageEnabled.Value || (Object)(object)health == (Object)null || IsPlayerTwoDead || requestedDamage <= 0f || computedDamage > 0f || !IsPlayerTwoComponent((Component)(object)health))
			{
				return false;
			}
			ClearDamageLocks(health);
			forcedDamage = requestedDamage;
			if (Plugin.DiagnosticsEnabled.Value && !_loggedPlayerTwoDamageOutputOverride)
			{
				_loggedPlayerTwoDamageOutputOverride = true;
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(113, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Forced player-two damage output from ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(computedDamage);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(forcedDamage);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; a cloned resistance/avoidance rule had zeroed a positive incoming hit.");
				}
				logger.LogInfo(val);
			}
			return true;
		}

		internal void BeforePlayerTwoDamageOnTouchCollision(DamageOnTouch damageOnTouch, Collider2D otherCollider)
		{
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Expected O, but got Unknown
			ClearDamageOnTouchState();
			if (!Plugin.ModEnabled.Value || (Object)(object)damageOnTouch == (Object)null || (Object)(object)otherCollider == (Object)null || (Object)(object)PlayerTwo == (Object)null || IsPlayerTwoDead || !IsPlayerTwoComponent((Component)(object)otherCollider))
			{
				return;
			}
			try
			{
				if (IsSamePlayer(ResolveLocalPlayerDamageSource(damageOnTouch), PlayerTwo))
				{
					return;
				}
				EnsurePlayerTwoHitCollider(PlayerTwo);
				Health health = ((AStatCharacter<PlayerStats>)(object)PlayerTwo).Health;
				if ((Object)(object)health != (Object)null)
				{
					ClearDamageLocks(health);
				}
				RemovePlayerTwoFromDamageIgnoreList(damageOnTouch, otherCollider, health);
				IncludePlayerTwoLayerInDamageMask(damageOnTouch, otherCollider);
				LogPlayerTwoDamageOnTouchCollision(damageOnTouch, otherCollider, health);
				if (!((Object)(object)health == (Object)null) && !(health.CurrentHealth <= 0f))
				{
					float damageOnTouchFallbackDamage = GetDamageOnTouchFallbackDamage(damageOnTouch);
					if (!(damageOnTouchFallbackDamage <= 0f) && CanDamageOnTouchReachPlayerTwo(damageOnTouch, otherCollider))
					{
						_damageOnTouchStateKey = BuildDamageOnTouchStateKey(damageOnTouch, otherCollider);
						_damageOnTouchStateHealth = health;
						_damageOnTouchStateBeforeHealth = health.CurrentHealth;
						_damageOnTouchStateFallbackDamage = damageOnTouchFallbackDamage;
						_damageOnTouchStateInvincibilityDuration = Mathf.Max(0f, damageOnTouch.InvincibilityDuration);
						_damageOnTouchStateContextualDeathTip = damageOnTouch.ContextualDeathTip;
						_damageOnTouchStateInstigator = GetDamageOnTouchInstigator(damageOnTouch);
						_damageOnTouchStateSourceName = ((Object)damageOnTouch).name;
					}
				}
			}
			catch (Exception ex)
			{
				if (Plugin.DiagnosticsEnabled.Value)
				{
					ManualLogSource logger = Plugin.Logger;
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(63, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Failed while preparing player two for DamageOnTouch collision: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					}
					logger.LogWarning(val);
				}
			}
		}

		internal void AfterPlayerTwoDamageOnTouchCollision(DamageOnTouch damageOnTouch, Collider2D otherCollider)
		{
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Expected O, but got Unknown
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Expected O, but got Unknown
			if (_damageOnTouchStateKey == 0 || (Object)(object)damageOnTouch == (Object)null || (Object)(object)otherCollider == (Object)null || _damageOnTouchStateKey != BuildDamageOnTouchStateKey(damageOnTouch, otherCollider) || (Object)(object)_damageOnTouchStateHealth == (Object)null || (Object)(object)PlayerTwo == (Object)null)
			{
				return;
			}
			Health damageOnTouchStateHealth = _damageOnTouchStateHealth;
			float damageOnTouchStateBeforeHealth = _damageOnTouchStateBeforeHealth;
			float damageOnTouchStateFallbackDamage = _damageOnTouchStateFallbackDamage;
			float damageOnTouchStateInvincibilityDuration = _damageOnTouchStateInvincibilityDuration;
			int damageOnTouchStateContextualDeathTip = _damageOnTouchStateContextualDeathTip;
			GameObject damageOnTouchStateInstigator = _damageOnTouchStateInstigator;
			string damageOnTouchStateSourceName = _damageOnTouchStateSourceName;
			ClearDamageOnTouchState();
			float currentHealth = damageOnTouchStateHealth.CurrentHealth;
			if (currentHealth < damageOnTouchStateBeforeHealth - 0.001f)
			{
				RecordPlayerTwoDamageResult(damageOnTouchStateHealth, "DamageOnTouch(" + damageOnTouchStateSourceName + ")", damageOnTouchStateBeforeHealth - currentHealth, damageOnTouchStateBeforeHealth);
			}
			else
			{
				if (IsPlayerTwoDead)
				{
					return;
				}
				bool flag = default(bool);
				try
				{
					ClearDamageLocks(damageOnTouchStateHealth);
					float currentHealth2 = damageOnTouchStateHealth.CurrentHealth;
					damageOnTouchStateHealth.Damage(damageOnTouchStateFallbackDamage, damageOnTouchStateInstigator, damageOnTouchStateInvincibilityDuration, damageOnTouchStateContextualDeathTip);
					damageOnTouchStateHealth.UpdateHealthBar(true);
					if (Plugin.DiagnosticsEnabled.Value && !_loggedPlayerTwoDamageOnTouchFallback)
					{
						_loggedPlayerTwoDamageOnTouchFallback = true;
						ManualLogSource logger = Plugin.Logger;
						BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(111, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Applied player-two DamageOnTouch fallback from ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(damageOnTouchStateSourceName);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; the normal touch-damage path saw P2 but left health unchanged.");
						}
						logger.LogInfo(val);
					}
					RecordPlayerTwoDamageResult(damageOnTouchStateHealth, "DamageOnTouch fallback(" + damageOnTouchStateSourceName + ")", damageOnTouchStateFallbackDamage, currentHealth2);
				}
				catch (Exception ex)
				{
					if (Plugin.DiagnosticsEnabled.Value)
					{
						ManualLogSource logger2 = Plugin.Logger;
						BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(57, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Failed while applying player-two DamageOnTouch fallback: ");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
						}
						logger2.LogWarning(val2);
					}
				}
			}
		}

		public bool IsPlayerTwoAttackableEntity(IAttackableEntity entity)
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			if (!Plugin.ModEnabled.Value || entity == null || (Object)(object)PlayerTwo == (Object)null || IsPlayerTwoDead)
			{
				return false;
			}
			try
			{
				Health health = entity.Health;
				Health health2 = ((AStatCharacter<PlayerStats>)(object)PlayerTwo).Health;
				return (Object)(object)health != (Object)null && (Object)(object)health2 != (Object)null && ((Object)health).GetInstanceID() == ((Object)health2).GetInstanceID();
			}
			catch (Exception ex)
			{
				if (Plugin.DiagnosticsEnabled.Value)
				{
					ManualLogSource logger = Plugin.Logger;
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(51, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Failed to compare attackable entity to player two: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					}
					logger.LogWarning(val);
				}
				return false;
			}
		}

		public bool IsPlayerOneAttackableEntity(IAttackableEntity entity)
		{
			return IsPlayerAttackableEntity(entity, PlayerOne, IsPlayerOneDead);
		}

		public bool TryOverrideLocalPlayerAllyStatus(AIDetectionController controller, IAttackableEntity target, out bool isAlly)
		{
			isAlly = false;
			if ((Object)(object)controller == (Object)null || target == null)
			{
				return false;
			}
			bool num = IsPlayerOneAttackableEntity(target);
			bool flag = IsPlayerTwoAttackableEntity(target);
			if (!num && !flag)
			{
				return false;
			}
			if (IsAiCharmedByLocalPlayer(controller))
			{
				isAlly = true;
				return true;
			}
			if (flag)
			{
				isAlly = false;
				return true;
			}
			return false;
		}

		public bool ShouldAiTreatPlayerTwoAsAttackable(AIDetectionController controller, IAttackableEntity target)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (!IsPlayerTwoAttackableEntity(target) || (Object)(object)controller == (Object)null || IsAiCharmedByLocalPlayer(controller) || !IsWithinAiRefreshDistance(controller, ((Component)PlayerTwo).transform.position))
			{
				return false;
			}
			LogPlayerTwoTargetConsidered(controller);
			RemovePlayerTwoFromAiIgnoreSet(controller, target);
			_playerTwoAiHudStatus = "P2 AI: SEEN " + ((Object)controller).name;
			return true;
		}

		public bool IsDestroyedOrDisabledAttackTarget(IAttackableEntity target)
		{
			if (target == null)
			{
				return true;
			}
			try
			{
				Health health = target.Health;
				return (Object)(object)health == (Object)null || (Object)(object)((Component)health).gameObject == (Object)null || !((Behaviour)health).isActiveAndEnabled;
			}
			catch
			{
				return true;
			}
		}

		public bool TryNormalizeLocalPlayerAttackScore(AIDetectionController controller, IAttackableEntity target, float distanceToTarget, float computedScore, out float normalizedScore)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			normalizedScore = computedScore;
			if ((Object)(object)controller == (Object)null || target == null)
			{
				return false;
			}
			bool num = IsPlayerOneAttackableEntity(target);
			bool flag = IsPlayerTwoAttackableEntity(target);
			if (!num && !flag)
			{
				return false;
			}
			if (IsAiCharmedByLocalPlayer(controller))
			{
				normalizedScore = 0f;
				return true;
			}
			normalizedScore = 1f / (1f + Mathf.Max(0f, distanceToTarget));
			if (Plugin.DiagnosticsEnabled.Value && !_loggedPlayerTwoAttackScoreForced)
			{
				_loggedPlayerTwoAttackScoreForced = true;
				ManualLogSource logger = Plugin.Logger;
				bool flag2 = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(104, 4, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Normalized local-player AI target scores by distance; sample target=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(flag ? "P2" : "P1");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", distance=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(distanceToTarget, "0.##");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", original=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(computedScore, "0.###");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", normalized=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(normalizedScore, "0.###");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				logger.LogInfo(val);
			}
			return true;
		}

		public void RefreshCharmedAiFriendliness(AIDetectionController controller)
		{
			if (Plugin.ModEnabled.Value && !((Object)(object)controller == (Object)null) && IsAiCharmedByLocalPlayer(controller))
			{
				ForgetLocalPlayerTarget(controller, PlayerOne);
				ForgetLocalPlayerTarget(controller, PlayerTwo);
				controller.ForceRefreshAttackTarget();
			}
		}

		public bool ShouldBypassPlayerTwoPreventBeingAttackedOnSight(Component preventComponent)
		{
			if (!IsPlayerTwoComponent(preventComponent) || IsPlayerTwoDead)
			{
				return false;
			}
			if (Plugin.DiagnosticsEnabled.Value && !_loggedPlayerTwoPreventSightBypass)
			{
				Plugin.Logger.LogInfo((object)"Bypassing cloned PreventBeingAttackedOnSight component for player two.");
				_loggedPlayerTwoPreventSightBypass = true;
			}
			return true;
		}

		public void RecordPlayerTwoDamageAttempt(Health health, string source, float damage)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			if (Plugin.DiagnosticsEnabled.Value && !_loggedPlayerTwoDamageAttempt && IsPlayerTwoComponent((Component)(object)health))
			{
				_loggedPlayerTwoDamageAttempt = true;
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(113, 6, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Observed damage attempt on player two via ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(source);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": requestedDamage=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(damage);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", currentHealth=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(health.CurrentHealth);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", maxHealth=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(health.MaximumHealth);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", invulnerable=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(health.Invulnerable);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", immune=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(health.ImmuneToDamage);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				logger.LogInfo(val);
			}
		}

		public void RecordPlayerTwoDamageResult(Health health, string source, float damage, float before)
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			if (Plugin.DiagnosticsEnabled.Value && !((Object)(object)health == (Object)null) && IsPlayerTwoComponent((Component)(object)health) && _playerTwoDamageResultLogs < 6)
			{
				float currentHealth = health.CurrentHealth;
				bool flag = currentHealth < before - 0.001f;
				_playerTwoDamageHudStatus = (flag ? $"P2 DMG: OK {Mathf.CeilToInt(before)}->{Mathf.CeilToInt(currentHealth)}" : $"P2 DMG: CHECK {Mathf.CeilToInt(before)}->{Mathf.CeilToInt(currentHealth)}");
				_playerTwoDamageResultLogs++;
				ManualLogSource logger = Plugin.Logger;
				bool flag2 = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(82, 6, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Player-two damage result via ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(source);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": requestedDamage=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(damage, "0.##");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", health ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(before, "0.##");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" -> ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(currentHealth, "0.##");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", decreased=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(flag);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", p2Dead=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(IsPlayerTwoDead);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				logger.LogInfo(val);
			}
		}

		public bool ShouldSuppressFriendlyFireDamage(Health targetHealth, GameObject instigator)
		{
			if (!Plugin.ModEnabled.Value || _applyingDiagnosticDamage || (Object)(object)targetHealth == (Object)null || (Object)(object)instigator == (Object)null)
			{
				return false;
			}
			PlayerCharacter componentInParent = ((Component)targetHealth).GetComponentInParent<PlayerCharacter>();
			PlayerCharacter sourcePlayer = ResolveLocalPlayerDamageSource(instigator);
			return ShouldSuppressLocalPlayerDamage(sourcePlayer, componentInParent, "Health.Damage");
		}

		public bool ShouldSuppressFriendlyFireCollision(DamageOnTouch damageOnTouch, Collider2D targetCollider)
		{
			if (!Plugin.ModEnabled.Value || (Object)(object)damageOnTouch == (Object)null || (Object)(object)targetCollider == (Object)null)
			{
				return false;
			}
			PlayerCharacter sourcePlayer = ResolveLocalPlayerDamageSource(damageOnTouch);
			PlayerCharacter componentInParent = ((Component)targetCollider).GetComponentInParent<PlayerCharacter>();
			return ShouldSuppressLocalPlayerDamage(sourcePlayer, componentInParent, "DamageOnTouch(" + ((Object)damageOnTouch).name + ")");
		}

		private bool ShouldSuppressLocalPlayerDamage(PlayerCharacter sourcePlayer, PlayerCharacter targetPlayer, string source)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			if (!IsTrackedLocalPlayer(sourcePlayer) || !IsTrackedLocalPlayer(targetPlayer))
			{
				return false;
			}
			bool flag = IsSamePlayer(sourcePlayer, targetPlayer);
			if (!flag && Plugin.FriendlyFireEnabled.Value)
			{
				return false;
			}
			if (Plugin.DiagnosticsEnabled.Value && !_loggedFriendlyFireSuppressed)
			{
				_loggedFriendlyFireSuppressed = true;
				string text = (flag ? "self damage" : "friendly fire");
				ManualLogSource logger = Plugin.Logger;
				bool flag2 = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(36, 4, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Suppressed local-player ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" via ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(source);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)sourcePlayer).name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" -> ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)targetPlayer).name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				logger.LogInfo(val);
			}
			return true;
		}

		private PlayerCharacter ResolveLocalPlayerDamageSource(DamageOnTouch damageOnTouch)
		{
			if ((Object)(object)damageOnTouch == (Object)null)
			{
				return null;
			}
			PlayerCharacter val = ResolveLocalPlayerDamageSource(damageOnTouch.DamageOwner);
			if (IsTrackedLocalPlayer(val))
			{
				return val;
			}
			val = ResolveLocalPlayerDamageSource(damageOnTouch.Owner);
			if (IsTrackedLocalPlayer(val))
			{
				return val;
			}
			return ResolveLocalPlayerDamageSource(((Component)damageOnTouch).gameObject);
		}

		private PlayerCharacter ResolveLocalPlayerDamageSource(GameObject sourceObject)
		{
			if ((Object)(object)sourceObject == (Object)null)
			{
				return null;
			}
			PlayerCharacter componentInParent = sourceObject.GetComponentInParent<PlayerCharacter>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				return componentInParent;
			}
			componentInParent = ResolveAttackOwner(sourceObject.GetComponentInParent<EICCharacterAttack>());
			return componentInParent ?? ResolveCurrentAttackOwner(sourceObject);
		}

		private PlayerCharacter ResolveAttackOwner(EICCharacterAttack attack)
		{
			if ((Object)(object)attack == (Object)null)
			{
				return null;
			}
			try
			{
				Character owner = ((Weapon)attack).Owner;
				PlayerCharacter val = ((owner != null) ? ((Component)owner).GetComponentInParent<PlayerCharacter>() : null);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
				IStatCharacter statCharacterOwner = attack.StatCharacterOwner;
				object obj;
				if (statCharacterOwner == null)
				{
					obj = null;
				}
				else
				{
					Health health = statCharacterOwner.Health;
					obj = ((health != null) ? ((Component)health).GetComponentInParent<PlayerCharacter>() : null);
				}
				val = (PlayerCharacter)obj;
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
				AAttackHandler attackHandler = attack.AttackHandler;
				return (attackHandler != null) ? ((Component)attackHandler).GetComponentInParent<PlayerCharacter>() : null;
			}
			catch
			{
				return null;
			}
		}

		private PlayerCharacter ResolveLocalPlayerOwner(Component component)
		{
			if ((Object)(object)component == (Object)null)
			{
				return null;
			}
			PlayerCharacter componentInParent = component.GetComponentInParent<PlayerCharacter>();
			if (IsPlayerOne(componentInParent) || IsPlayerTwo(componentInParent))
			{
				return componentInParent;
			}
			componentInParent = ResolveAttackOwner(component.GetComponentInParent<EICCharacterAttack>());
			if (IsPlayerOne(componentInParent) || IsPlayerTwo(componentInParent))
			{
				return componentInParent;
			}
			componentInParent = (((Object)(object)component.gameObject != (Object)null) ? ResolveCurrentAttackOwner(component.gameObject) : null);
			if (!IsPlayerOne(componentInParent) && !IsPlayerTwo(componentInParent))
			{
				return null;
			}
			return componentInParent;
		}

		private bool TryGetLocalPlayerAim(Component component, out PlayerCharacter player, out Vector3 aim)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.ModEnabled.Value)
			{
				player = null;
				aim = Vector3.zero;
				return false;
			}
			player = ResolveLocalPlayerOwner(component);
			if (IsPlayerTwo(player))
			{
				aim = GetPlayerTwoAimVector();
				return true;
			}
			if (_playerOneAimControlled && IsPlayerOne(player))
			{
				aim = new Vector3(_playerOneAim.x, _playerOneAim.y, 0f);
				return true;
			}
			player = null;
			aim = Vector3.zero;
			return false;
		}

		private bool IsLocalPlayerDead(PlayerCharacter player)
		{
			if (!IsPlayerTwo(player))
			{
				return IsPlayerOneDead;
			}
			return IsPlayerTwoDead;
		}

		private PlayerCharacter ResolveCurrentAttackOwner(GameObject sourceObject)
		{
			if ((Object)(object)sourceObject == (Object)null)
			{
				return null;
			}
			Transform transform = sourceObject.transform;
			PlayerCharacter[] array = (PlayerCharacter[])(object)new PlayerCharacter[2] { PlayerTwo, PlayerOne };
			foreach (PlayerCharacter val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				foreach (AAttackHandler componentsInChild in ((Component)val).GetComponentsInChildren<AAttackHandler>(true))
				{
					object obj;
					if (componentsInChild == null)
					{
						obj = null;
					}
					else
					{
						Weapon currentWeapon = ((CharacterHandleWeapon)componentsInChild).CurrentWeapon;
						obj = ((currentWeapon != null) ? ((Il2CppObjectBase)currentWeapon).TryCast<EICCharacterAttack>() : null);
					}
					EICCharacterAttack val2 = (EICCharacterAttack)obj;
					if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).gameObject == (Object)null))
					{
						Transform transform2 = ((Component)val2).transform;
						if (((Object)((Component)val2).gameObject).GetInstanceID() == ((Object)sourceObject).GetInstanceID() || ((Object)(object)transform != (Object)null && (Object)(object)transform2 != (Object)null && transform.IsChildOf(transform2)))
						{
							return val;
						}
						WeaponAim weaponAim = val2.WeaponAim;
						if ((Object)(object)weaponAim != (Object)null && (Object)(object)((Component)weaponAim).gameObject != (Object)null && ((Object)((Component)weaponAim).gameObject).GetInstanceID() == ((Object)sourceObject).GetInstanceID())
						{
							return val;
						}
					}
				}
			}
			return null;
		}

		private bool IsPlayerTwo(PlayerCharacter player)
		{
			if ((Object)(object)player != (Object)null)
			{
				if (_playerTwoId == 0 || ((Object)player).GetInstanceID() != _playerTwoId)
				{
					if ((Object)(object)((Component)player).gameObject != (Object)null)
					{
						return ((Object)((Component)player).gameObject).name.StartsWith("LocalMultiplayer_Player2", StringComparison.Ordinal);
					}
					return false;
				}
				return true;
			}
			return false;
		}

		private bool IsTrackedLocalPlayer(PlayerCharacter player)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)((Component)player).gameObject == (Object)null)
			{
				return false;
			}
			if (!IsSamePlayer(player, PlayerOne) && !IsSamePlayer(player, PlayerTwo) && !((Object)((Component)player).gameObject).name.StartsWith("LocalMultiplayer_Player2", StringComparison.Ordinal))
			{
				return ((Object)((Component)player).gameObject).name.StartsWith("LocalMultiplayer_Player1_PendingDestroy", StringComparison.Ordinal);
			}
			return true;
		}

		private static GameObject GetDamageOnTouchInstigator(DamageOnTouch damageOnTouch)
		{
			if ((Object)(object)damageOnTouch == (Object)null)
			{
				return null;
			}
			if (!((Object)(object)damageOnTouch.DamageOwner != (Object)null))
			{
				return damageOnTouch.Owner;
			}
			return damageOnTouch.DamageOwner;
		}

		private static float GetDamageOnTouchFallbackDamage(DamageOnTouch damageOnTouch)
		{
			if ((Object)(object)damageOnTouch == (Object)null)
			{
				return 0f;
			}
			float num = Mathf.Max(0f, damageOnTouch.MinDamageCaused);
			float num2 = Mathf.Max(num, damageOnTouch.MaxDamageCaused);
			if (num2 <= 0f)
			{
				return 0f;
			}
			if (!Mathf.Approximately(num, num2))
			{
				return Random.Range(num, num2);
			}
			return num2;
		}

		private bool CanDamageOnTouchReachPlayerTwo(DamageOnTouch damageOnTouch, Collider2D otherCollider)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			if ((Object)(object)damageOnTouch == (Object)null || (Object)(object)otherCollider == (Object)null || (Object)(object)((Component)otherCollider).gameObject == (Object)null)
			{
				return false;
			}
			try
			{
				return damageOnTouch.EvaluateAvailability(((Component)otherCollider).gameObject);
			}
			catch (Exception ex)
			{
				if (Plugin.DiagnosticsEnabled.Value)
				{
					ManualLogSource logger = Plugin.Logger;
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(105, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Could not evaluate DamageOnTouch availability for player two; fallback will remain enabled for this hit. ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					}
					logger.LogWarning(val);
				}
				return true;
			}
		}

		private void ClearDamageOnTouchState()
		{
			_damageOnTouchStateKey = 0;
			_damageOnTouchStateHealth = null;
			_damageOnTouchStateInstigator = null;
			_damageOnTouchStateBeforeHealth = 0f;
			_damageOnTouchStateFallbackDamage = 0f;
			_damageOnTouchStateInvincibilityDuration = 0f;
			_damageOnTouchStateContextualDeathTip = 0;
			_damageOnTouchStateSourceName = string.Empty;
		}

		private void ResetHudStatuses()
		{
			_playerTwoDamageHudStatus = "P2 DMG: WAIT";
			_playerTwoAiHudStatus = "P2 AI: WAIT";
			_cameraHudStatus = "CAM: WAIT";
		}

		private static int BuildDamageOnTouchStateKey(DamageOnTouch damageOnTouch, Collider2D otherCollider)
		{
			if ((Object)(object)damageOnTouch == (Object)null || (Object)(object)otherCollider == (Object)null)
			{
				return 0;
			}
			return (((Object)damageOnTouch).GetInstanceID() * 397) ^ ((Object)otherCollider).GetInstanceID();
		}

		private void ResetForSceneChanges()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Expected O, but got Unknown
			Scene activeScene = SceneManager.GetActiveScene();
			if (((Scene)(ref activeScene)).handle != _sceneHandle)
			{
				_sceneHandle = ((Scene)(ref activeScene)).handle;
				PlayerOne = null;
				PlayerTwo = null;
				_playerOneId = 0;
				_playerTwoId = 0;
				_cameraId = 0;
				_cameraEnforcerId = 0;
				_baseOrthographicSize = 0f;
				_smoothedOrthographicSize = 0f;
				_smoothedCameraCenter = Vector2.zero;
				_hasSharedCameraState = false;
				SharedCameraMidpointError = float.PositiveInfinity;
				RenderCameraMidpointError = float.PositiveInfinity;
				ClearSharedNightVisionTracking();
				_nextSpawnAttemptAt = Time.unscaledTime + 1f;
				_nextSpawnWaitLogAt = 0f;
				_nextAiRefreshAt = 0f;
				_lastSpawnWaitReason = string.Empty;
				ResetHudStatuses();
				ClearDamageOnTouchState();
				_loggedPlayerTwoInput = false;
				_loggedFilteredStockInput = false;
				_loggedPlayerTwoDamageAttempt = false;
				_loggedPlayerTwoDamageOutputOverride = false;
				_loggedPlayerTwoMasterHealthCleared = false;
				_loggedPlayerTwoColliderState = false;
				_loggedPlayerTwoPhysicalColliderEnabled = false;
				_loggedPlayerTwoRigidbodyEnabled = false;
				_loggedPlayerTwoDamageOnTouchCollision = false;
				_loggedPlayerTwoDamageOnTouchMaskPatched = false;
				_loggedPlayerTwoDamageOnTouchIgnoreCleared = false;
				_loggedPlayerTwoDamageOnTouchFallback = false;
				_loggedPlayerTwoAiIgnoreCleared = false;
				_loggedPlayerTwoDirectAiRegistration = false;
				_loggedPlayerTwoDirectAiRegistrationFailure = false;
				_loggedPlayerTwoAttackScoreForced = false;
				_loggedPlayerTwoTargetConsidered = false;
				_loggedPlayerTwoPreventSightBypass = false;
				_loggedFriendlyFireSuppressed = false;
				_playerTwoDamageResultLogs = 0;
				_playerOneDead = false;
				_playerOneAwaitingRevive = false;
				_playerTwoDead = false;
				_playerTwoAwaitingRevive = false;
				_playerOneObjectName = "PlayerCharacter";
				_playerOneSpriteColors.Clear();
				_playerOneMove = Vector2.zero;
				ResetMushroomEffectOwnership();
				_evolutionPickerOpen = false;
				_suppressedPlayerDeathDropCount = 0;
				_previousDamagePlayerTwoHeld = false;
				_previousDamagePlayerOneHeld = false;
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(44, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Scene changed to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Scene)(ref activeScene)).name);
					((BepInExLogInt